diff --git a/packages/kbn-optimizer/limits.yml b/packages/kbn-optimizer/limits.yml index 1af74aa3d882..f93849e011d4 100644 --- a/packages/kbn-optimizer/limits.yml +++ b/packages/kbn-optimizer/limits.yml @@ -108,4 +108,3 @@ pageLoadAssetSize: fileUpload: 25664 banners: 17946 mapsEms: 26072 - cases: 102558 diff --git a/x-pack/plugins/cases/common/api/index.ts b/x-pack/plugins/cases/common/api/index.ts index 2ef03dd96e31..7780564089d3 100644 --- a/x-pack/plugins/cases/common/api/index.ts +++ b/x-pack/plugins/cases/common/api/index.ts @@ -7,7 +7,6 @@ export * from './cases'; export * from './connectors'; -export * from './helpers'; export * from './runtime_types'; export * from './saved_object'; export * from './user'; diff --git a/x-pack/plugins/cases/common/constants.ts b/x-pack/plugins/cases/common/constants.ts index d779ccd0b7ab..1e7cff99a00b 100644 --- a/x-pack/plugins/cases/common/constants.ts +++ b/x-pack/plugins/cases/common/constants.ts @@ -5,9 +5,8 @@ * 2.0. */ -// The DEFAULT_MAX_SIGNALS value should match the one in `x-pack/plugins/security_solution/common/constants.ts` -// If either changes, engineer should ensure both values are updated -const DEFAULT_MAX_SIGNALS = 100; +import { DEFAULT_MAX_SIGNALS } from '../../security_solution/common/constants'; + export const APP_ID = 'cases'; /** diff --git a/x-pack/plugins/cases/common/index.ts b/x-pack/plugins/cases/common/index.ts deleted file mode 100644 index 37c11172b50b..000000000000 --- a/x-pack/plugins/cases/common/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export * from './constants'; -export * from './api'; diff --git a/x-pack/plugins/cases/kibana.json b/x-pack/plugins/cases/kibana.json index 27b36d7e86e1..1aaf84decbe3 100644 --- a/x-pack/plugins/cases/kibana.json +++ b/x-pack/plugins/cases/kibana.json @@ -2,13 +2,12 @@ "configPath": ["xpack", "cases"], "id": "cases", "kibanaVersion": "kibana", - "extraPublicDirs": ["common"], - "requiredPlugins": ["actions", "esUiShared", "kibanaReact", "triggersActionsUi"], + "requiredPlugins": ["actions", "securitySolution"], "optionalPlugins": [ "spaces", "security" ], "server": true, - "ui": true, + "ui": false, "version": "8.0.0" } diff --git a/x-pack/plugins/cases/public/common/errors.ts b/x-pack/plugins/cases/public/common/errors.ts deleted file mode 100644 index 6edef08c1f4b..000000000000 --- a/x-pack/plugins/cases/public/common/errors.ts +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { has } from 'lodash/fp'; - -export interface AppError { - name: string; - message: string; - body: { - message: string; - }; -} - -export interface KibanaError extends AppError { - body: { - message: string; - statusCode: number; - }; -} - -export interface CasesAppError extends AppError { - body: { - message: string; - status_code: number; - }; -} - -export const isKibanaError = (error: unknown): error is KibanaError => - has('message', error) && has('body.message', error) && has('body.statusCode', error); - -export const isCasesAppError = (error: unknown): error is CasesAppError => - has('message', error) && has('body.message', error) && has('body.status_code', error); - -export const isAppError = (error: unknown): error is AppError => - isKibanaError(error) || isCasesAppError(error); diff --git a/x-pack/plugins/cases/public/common/lib/kibana/__mocks__/index.ts b/x-pack/plugins/cases/public/common/lib/kibana/__mocks__/index.ts deleted file mode 100644 index 392b71befe2b..000000000000 --- a/x-pack/plugins/cases/public/common/lib/kibana/__mocks__/index.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { notificationServiceMock } from '../../../../../../../../src/core/public/mocks'; -import { - createKibanaContextProviderMock, - createStartServicesMock, - createWithKibanaMock, -} from '../kibana_react.mock'; - -export const KibanaServices = { get: jest.fn(), getKibanaVersion: jest.fn(() => '8.0.0') }; -export const useKibana = jest.fn().mockReturnValue({ - services: createStartServicesMock(), -}); - -export const useHttp = jest.fn().mockReturnValue(createStartServicesMock().http); -export const useTimeZone = jest.fn(); -export const useDateFormat = jest.fn(); -export const useBasePath = jest.fn(() => '/test/base/path'); -export const useToasts = jest - .fn() - .mockReturnValue(notificationServiceMock.createStartContract().toasts); -export const useCurrentUser = jest.fn(); -export const withKibana = jest.fn(createWithKibanaMock()); -export const KibanaContextProvider = jest.fn(createKibanaContextProviderMock()); -export const useGetUserSavedObjectPermissions = jest.fn(); diff --git a/x-pack/plugins/cases/public/common/lib/kibana/index.ts b/x-pack/plugins/cases/public/common/lib/kibana/index.ts deleted file mode 100644 index a7f3c1e70ced..000000000000 --- a/x-pack/plugins/cases/public/common/lib/kibana/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export * from './kibana_react'; -export * from './services'; diff --git a/x-pack/plugins/cases/public/common/lib/kibana/kibana_react.mock.ts b/x-pack/plugins/cases/public/common/lib/kibana/kibana_react.mock.ts deleted file mode 100644 index 326163f6cdc0..000000000000 --- a/x-pack/plugins/cases/public/common/lib/kibana/kibana_react.mock.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { RecursivePartial } from '@elastic/eui/src/components/common'; -import { coreMock } from '../../../../../../../src/core/public/mocks'; -import { KibanaContextProvider } from '../../../../../../../src/plugins/kibana_react/public'; -import { StartServices } from '../../../types'; -import { EuiTheme } from '../../../../../../../src/plugins/kibana_react/common'; - -export const createStartServicesMock = (): StartServices => - (coreMock.createStart() as unknown) as StartServices; - -export const createWithKibanaMock = () => { - const services = createStartServicesMock(); - - return (Component: unknown) => (props: unknown) => { - return React.createElement(Component as string, { ...(props as object), kibana: { services } }); - }; -}; - -export const createKibanaContextProviderMock = () => { - const services = createStartServicesMock(); - - return ({ children }: { children: React.ReactNode }) => - React.createElement(KibanaContextProvider, { services }, children); -}; - -export const getMockTheme = (partialTheme: RecursivePartial): EuiTheme => - partialTheme as EuiTheme; diff --git a/x-pack/plugins/cases/public/common/lib/kibana/kibana_react.ts b/x-pack/plugins/cases/public/common/lib/kibana/kibana_react.ts deleted file mode 100644 index e23fad392040..000000000000 --- a/x-pack/plugins/cases/public/common/lib/kibana/kibana_react.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - KibanaContextProvider, - useKibana, -} from '../../../../../../../src/plugins/kibana_react/public'; -import { StartServices } from '../../../types'; - -const useTypedKibana = () => useKibana(); - -export { KibanaContextProvider, useTypedKibana as useKibana }; diff --git a/x-pack/plugins/cases/public/common/lib/kibana/services.ts b/x-pack/plugins/cases/public/common/lib/kibana/services.ts deleted file mode 100644 index 94487bd3ca5e..000000000000 --- a/x-pack/plugins/cases/public/common/lib/kibana/services.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { CoreStart } from 'kibana/public'; - -type GlobalServices = Pick; - -export class KibanaServices { - private static kibanaVersion?: string; - private static services?: GlobalServices; - - public static init({ http, kibanaVersion }: GlobalServices & { kibanaVersion: string }) { - this.services = { http }; - this.kibanaVersion = kibanaVersion; - } - - public static get(): GlobalServices { - if (!this.services) { - this.throwUninitializedError(); - } - - return this.services; - } - - public static getKibanaVersion(): string { - if (!this.kibanaVersion) { - this.throwUninitializedError(); - } - - return this.kibanaVersion; - } - - private static throwUninitializedError(): never { - throw new Error( - 'Kibana services not initialized - are you trying to import this module from outside of the Cases app?' - ); - } -} diff --git a/x-pack/plugins/cases/public/common/mock/index.ts b/x-pack/plugins/cases/public/common/mock/index.ts deleted file mode 100644 index add4c1c206dd..000000000000 --- a/x-pack/plugins/cases/public/common/mock/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export * from './test_providers'; diff --git a/x-pack/plugins/cases/public/common/mock/kibana_react.mock.ts b/x-pack/plugins/cases/public/common/mock/kibana_react.mock.ts deleted file mode 100644 index 274462aec575..000000000000 --- a/x-pack/plugins/cases/public/common/mock/kibana_react.mock.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { CoreStart } from 'kibana/public'; -import { coreMock } from '../../../../../../src/core/public/mocks'; -import React from 'react'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { KibanaContextProvider } from '../../../../../../src/plugins/kibana_react/public/context'; - -export const createStartServicesMock = (): CoreStart => { - const core = coreMock.createStart(); - return (core as unknown) as CoreStart; -}; -export const createKibanaContextProviderMock = () => { - const services = coreMock.createStart(); - - return ({ children }: { children: React.ReactNode }) => - React.createElement(KibanaContextProvider, { services }, children); -}; diff --git a/x-pack/plugins/cases/public/common/mock/test_providers.tsx b/x-pack/plugins/cases/public/common/mock/test_providers.tsx deleted file mode 100644 index 4e40f3b3cb74..000000000000 --- a/x-pack/plugins/cases/public/common/mock/test_providers.tsx +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import euiDarkVars from '@elastic/eui/dist/eui_theme_dark.json'; -import { I18nProvider } from '@kbn/i18n/react'; -import React from 'react'; -import { BehaviorSubject } from 'rxjs'; -import { ThemeProvider } from 'styled-components'; -import { createKibanaContextProviderMock, createStartServicesMock } from './kibana_react.mock'; -import { FieldHook } from '../shared_imports'; - -interface Props { - children: React.ReactNode; -} - -export const kibanaObservable = new BehaviorSubject(createStartServicesMock()); - -window.scrollTo = jest.fn(); -const MockKibanaContextProvider = createKibanaContextProviderMock(); - -/** A utility for wrapping children in the providers required to run most tests */ -const TestProvidersComponent: React.FC = ({ children }) => ( - - - ({ eui: euiDarkVars, darkMode: true })}>{children} - - -); - -export const TestProviders = React.memo(TestProvidersComponent); - -export const useFormFieldMock = (options?: Partial>): FieldHook => { - 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, - }; -}; diff --git a/x-pack/plugins/cases/public/common/shared_imports.ts b/x-pack/plugins/cases/public/common/shared_imports.ts deleted file mode 100644 index 675204076b02..000000000000 --- a/x-pack/plugins/cases/public/common/shared_imports.ts +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export { - getUseField, - getFieldValidityAndErrorMessage, - FieldHook, - FieldValidateResponse, - FIELD_TYPES, - Form, - FormData, - FormDataProvider, - FormHook, - FormSchema, - UseField, - UseMultiFields, - useForm, - useFormContext, - useFormData, - ValidationError, - ValidationFunc, - VALIDATION_TYPES, -} from '../../../../../src/plugins/es_ui_shared/static/forms/hook_form_lib'; -export { - Field, - SelectField, -} from '../../../../../src/plugins/es_ui_shared/static/forms/components'; -export { fieldValidators } from '../../../../../src/plugins/es_ui_shared/static/forms/helpers'; -export { ERROR_CODE } from '../../../../../src/plugins/es_ui_shared/static/forms/helpers/field_validators/types'; diff --git a/x-pack/plugins/cases/public/common/test_utils.ts b/x-pack/plugins/cases/public/common/test_utils.ts deleted file mode 100644 index f6ccf28bcb64..000000000000 --- a/x-pack/plugins/cases/public/common/test_utils.ts +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -/** - * Convenience utility to remove text appended to links by EUI - */ -export const removeExternalLinkText = (str: string) => - str.replace(/\(opens in a new tab or window\)/g, ''); diff --git a/x-pack/plugins/cases/public/common/translations.ts b/x-pack/plugins/cases/public/common/translations.ts deleted file mode 100644 index 881acb9d4c90..000000000000 --- a/x-pack/plugins/cases/public/common/translations.ts +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; - -export const SAVED_OBJECT_NO_PERMISSIONS_TITLE = i18n.translate( - 'xpack.cases.caseSavedObjectNoPermissionsTitle', - { - defaultMessage: 'Kibana feature privileges required', - } -); - -export const SAVED_OBJECT_NO_PERMISSIONS_MSG = i18n.translate( - 'xpack.cases.caseSavedObjectNoPermissionsMessage', - { - defaultMessage: - 'To view cases, you must have privileges for the Saved Object Management 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', -}); - -export const CANCEL = i18n.translate('xpack.cases.caseView.cancel', { - defaultMessage: 'Cancel', -}); - -export const DELETE_CASE = i18n.translate('xpack.cases.confirmDeleteCase.deleteCase', { - defaultMessage: 'Delete case', -}); - -export const DELETE_CASES = i18n.translate('xpack.cases.confirmDeleteCase.deleteCases', { - defaultMessage: 'Delete cases', -}); - -export const NAME = i18n.translate('xpack.cases.caseView.name', { - defaultMessage: 'Name', -}); - -export const OPENED_ON = i18n.translate('xpack.cases.caseView.openedOn', { - defaultMessage: 'Opened on', -}); - -export const CLOSED_ON = i18n.translate('xpack.cases.caseView.closedOn', { - defaultMessage: 'Closed on', -}); - -export const REPORTER = i18n.translate('xpack.cases.caseView.reporterLabel', { - defaultMessage: 'Reporter', -}); - -export const PARTICIPANTS = i18n.translate('xpack.cases.caseView.particpantsLabel', { - 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', -}); - -export const DESCRIPTION = i18n.translate('xpack.cases.caseView.description', { - defaultMessage: 'Description', -}); - -export const DESCRIPTION_REQUIRED = i18n.translate( - 'xpack.cases.createCase.descriptionFieldRequiredError', - { - defaultMessage: 'A description is required.', - } -); - -export const COMMENT_REQUIRED = i18n.translate('xpack.cases.caseView.commentFieldRequiredError', { - defaultMessage: 'A comment is required.', -}); - -export const REQUIRED_FIELD = i18n.translate('xpack.cases.caseView.fieldRequiredError', { - defaultMessage: 'Required field', -}); - -export const EDIT = i18n.translate('xpack.cases.caseView.edit', { - defaultMessage: 'Edit', -}); - -export const OPTIONAL = i18n.translate('xpack.cases.caseView.optional', { - defaultMessage: 'Optional', -}); - -export const PAGE_TITLE = i18n.translate('xpack.cases.pageTitle', { - defaultMessage: 'Cases', -}); - -export const CREATE_CASE = i18n.translate('xpack.cases.caseView.createCase', { - defaultMessage: 'Create case', -}); - -export const CLOSE_CASE = i18n.translate('xpack.cases.caseView.closeCase', { - defaultMessage: 'Close case', -}); - -export const MARK_CASE_IN_PROGRESS = i18n.translate('xpack.cases.caseView.markInProgress', { - defaultMessage: 'Mark in progress', -}); - -export const REOPEN_CASE = i18n.translate('xpack.cases.caseView.reopenCase', { - defaultMessage: 'Reopen case', -}); - -export const OPEN_CASE = i18n.translate('xpack.cases.caseView.openCase', { - defaultMessage: 'Open case', -}); - -export const CASE_NAME = i18n.translate('xpack.cases.caseView.caseName', { - defaultMessage: 'Case name', -}); - -export const TO = i18n.translate('xpack.cases.caseView.to', { - defaultMessage: 'to', -}); - -export const TAGS = i18n.translate('xpack.cases.caseView.tags', { - defaultMessage: 'Tags', -}); - -export const ACTIONS = i18n.translate('xpack.cases.allCases.actions', { - defaultMessage: 'Actions', -}); - -export const NO_TAGS_AVAILABLE = i18n.translate('xpack.cases.allCases.noTagsAvailable', { - defaultMessage: 'No tags available', -}); - -export const NO_REPORTERS_AVAILABLE = i18n.translate('xpack.cases.caseView.noReportersAvailable', { - defaultMessage: 'No reporters available.', -}); - -export const COMMENTS = i18n.translate('xpack.cases.allCases.comments', { - defaultMessage: 'Comments', -}); - -export const TAGS_HELP = i18n.translate('xpack.cases.createCase.fieldTagsHelpText', { - defaultMessage: - 'Type one or more custom identifying tags for this case. Press enter after each tag to begin a new one.', -}); - -export const NO_TAGS = i18n.translate('xpack.cases.caseView.noTags', { - defaultMessage: 'No tags are currently assigned to this case.', -}); - -export const TITLE_REQUIRED = i18n.translate('xpack.cases.createCase.titleFieldRequiredError', { - defaultMessage: 'A title is required.', -}); - -export const CONFIGURE_CASES_PAGE_TITLE = i18n.translate('xpack.cases.configureCases.headerTitle', { - defaultMessage: 'Configure cases', -}); - -export const CONFIGURE_CASES_BUTTON = i18n.translate('xpack.cases.configureCasesButton', { - defaultMessage: 'Edit external connection', -}); - -export const ADD_COMMENT = i18n.translate('xpack.cases.caseView.comment.addComment', { - defaultMessage: 'Add comment', -}); - -export const ADD_COMMENT_HELP_TEXT = i18n.translate( - 'xpack.cases.caseView.comment.addCommentHelpText', - { - defaultMessage: 'Add a new comment...', - } -); - -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', -}); - -export const UNKNOWN = i18n.translate('xpack.cases.caseView.unknown', { - defaultMessage: 'Unknown', -}); - -export const MARKED_CASE_AS = i18n.translate('xpack.cases.caseView.markedCaseAs', { - defaultMessage: 'marked case as', -}); - -export const OPEN_CASES = i18n.translate('xpack.cases.caseTable.openCases', { - defaultMessage: 'Open cases', -}); - -export const CLOSED_CASES = i18n.translate('xpack.cases.caseTable.closedCases', { - defaultMessage: 'Closed cases', -}); - -export const IN_PROGRESS_CASES = i18n.translate('xpack.cases.caseTable.inProgressCases', { - defaultMessage: 'In progress cases', -}); - -export const SYNC_ALERTS_SWITCH_LABEL_ON = i18n.translate( - 'xpack.cases.settings.syncAlertsSwitchLabelOn', - { - defaultMessage: 'On', - } -); - -export const SYNC_ALERTS_SWITCH_LABEL_OFF = i18n.translate( - 'xpack.cases.settings.syncAlertsSwitchLabelOff', - { - defaultMessage: 'Off', - } -); - -export const SYNC_ALERTS_HELP = i18n.translate('xpack.cases.components.create.syncAlertHelpText', { - defaultMessage: - 'Enabling this option will sync the status of alerts in this case with the case status.', -}); - -export const ALERT = i18n.translate('xpack.cases.common.alertLabel', { - defaultMessage: 'Alert', -}); - -export const ALERT_ADDED_TO_CASE = i18n.translate('xpack.cases.common.alertAddedToCase', { - defaultMessage: 'added to case', -}); - -export const SELECTABLE_MESSAGE_COLLECTIONS = i18n.translate( - 'xpack.cases.common.allCases.table.selectableMessageCollections', - { - defaultMessage: 'Cases with sub-cases cannot be selected', - } -); diff --git a/x-pack/plugins/cases/public/components/__mock__/form.ts b/x-pack/plugins/cases/public/components/__mock__/form.ts deleted file mode 100644 index 6d3e8353e630..000000000000 --- a/x-pack/plugins/cases/public/components/__mock__/form.ts +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { useForm } from '../../../../../../src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_form'; -import { useFormData } from '../../../../../../src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_form_data'; - -jest.mock('../../../../../../src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_form'); -jest.mock( - '../../../../../../src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_form_data' -); - -export const mockFormHook = { - isSubmitted: false, - isSubmitting: false, - isValid: true, - submit: jest.fn(), - subscribe: jest.fn(), - setFieldValue: jest.fn(), - setFieldErrors: jest.fn(), - getFields: jest.fn(), - getFormData: jest.fn(), - /* Returns a list of all errors in the form */ - getErrors: jest.fn(), - reset: jest.fn(), - __options: {}, - __formData$: {}, - __addField: jest.fn(), - __removeField: jest.fn(), - __validateFields: jest.fn(), - __updateFormDataAt: jest.fn(), - __readFieldConfigFromSchema: jest.fn(), - __getFieldDefaultValue: jest.fn(), -}; - -export const getFormMock = (sampleData: any) => ({ - ...mockFormHook, - submit: () => - Promise.resolve({ - data: sampleData, - isValid: true, - }), - getFormData: () => sampleData, -}); - -export const useFormMock = useForm as jest.Mock; -export const useFormDataMock = useFormData as jest.Mock; diff --git a/x-pack/plugins/cases/public/components/configure_cases/__mock__/index.tsx b/x-pack/plugins/cases/public/components/configure_cases/__mock__/index.tsx deleted file mode 100644 index e3abbeadd2d3..000000000000 --- a/x-pack/plugins/cases/public/components/configure_cases/__mock__/index.tsx +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { ConnectorTypes } from '../../../../common'; -import { ActionConnector } from '../../../containers/configure/types'; -import { UseConnectorsResponse } from '../../../containers/configure/use_connectors'; -import { ReturnUseCaseConfigure } from '../../../containers/configure/use_configure'; -import { UseActionTypesResponse } from '../../../containers/configure/use_action_types'; -import { connectorsMock, actionTypesMock } from '../../../containers/configure/mock'; -export { mappings } from '../../../containers/configure/mock'; -export const connectors: ActionConnector[] = connectorsMock; - -export const searchURL = - '?timerange=(global:(linkTo:!(),timerange:(from:1585487656371,fromStr:now-24h,kind:relative,to:1585574056371,toStr:now)),timeline:(linkTo:!(),timerange:(from:1585227005527,kind:absolute,to:1585313405527)))'; - -export const useCaseConfigureResponse: ReturnUseCaseConfigure = { - closureType: 'close-by-user', - connector: { - id: 'none', - name: 'none', - type: ConnectorTypes.none, - fields: null, - }, - currentConfiguration: { - connector: { - id: 'none', - name: 'none', - type: ConnectorTypes.none, - fields: null, - }, - closureType: 'close-by-user', - }, - firstLoad: false, - loading: false, - mappings: [], - persistCaseConfigure: jest.fn(), - persistLoading: false, - refetchCaseConfigure: jest.fn(), - setClosureType: jest.fn(), - setConnector: jest.fn(), - setCurrentConfiguration: jest.fn(), - setMappings: jest.fn(), - version: '', -}; - -export const useConnectorsResponse: UseConnectorsResponse = { - loading: false, - connectors, - refetchConnectors: jest.fn(), -}; - -export const useActionTypesResponse: UseActionTypesResponse = { - loading: false, - actionTypes: actionTypesMock, - refetchActionTypes: jest.fn(), -}; diff --git a/x-pack/plugins/cases/public/components/configure_cases/closure_options.test.tsx b/x-pack/plugins/cases/public/components/configure_cases/closure_options.test.tsx deleted file mode 100644 index 56123a934d51..000000000000 --- a/x-pack/plugins/cases/public/components/configure_cases/closure_options.test.tsx +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { mount, ReactWrapper } from 'enzyme'; - -import { ClosureOptions, ClosureOptionsProps } from './closure_options'; -import { TestProviders } from '../../common/mock'; -import { ClosureOptionsRadio } from './closure_options_radio'; - -describe('ClosureOptions', () => { - let wrapper: ReactWrapper; - const onChangeClosureType = jest.fn(); - const props: ClosureOptionsProps = { - disabled: false, - closureTypeSelected: 'close-by-user', - onChangeClosureType, - }; - - beforeAll(() => { - wrapper = mount(, { wrappingComponent: TestProviders }); - }); - - test('it shows the closure options form group', () => { - expect( - wrapper.find('[data-test-subj="case-closure-options-form-group"]').first().exists() - ).toBe(true); - }); - - test('it shows the closure options form row', () => { - expect(wrapper.find('[data-test-subj="case-closure-options-form-row"]').first().exists()).toBe( - true - ); - }); - - test('it shows closure options', () => { - expect(wrapper.find('[data-test-subj="case-closure-options-radio"]').first().exists()).toBe( - true - ); - }); - - test('it pass the correct props to child', () => { - const closureOptionsRadioComponent = wrapper.find(ClosureOptionsRadio); - expect(closureOptionsRadioComponent.props().disabled).toEqual(false); - expect(closureOptionsRadioComponent.props().closureTypeSelected).toEqual('close-by-user'); - expect(closureOptionsRadioComponent.props().onChangeClosureType).toEqual(onChangeClosureType); - }); - - test('the closure type is changed successfully', () => { - wrapper.find('input[id="close-by-pushing"]').simulate('change'); - - expect(onChangeClosureType).toHaveBeenCalledWith('close-by-pushing'); - }); -}); diff --git a/x-pack/plugins/cases/public/components/configure_cases/closure_options.tsx b/x-pack/plugins/cases/public/components/configure_cases/closure_options.tsx deleted file mode 100644 index ba892116320c..000000000000 --- a/x-pack/plugins/cases/public/components/configure_cases/closure_options.tsx +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { EuiDescribedFormGroup, EuiFormRow } from '@elastic/eui'; - -import { ClosureType } from '../../containers/configure/types'; -import { ClosureOptionsRadio } from './closure_options_radio'; -import * as i18n from './translations'; - -export interface ClosureOptionsProps { - closureTypeSelected: ClosureType; - disabled: boolean; - onChangeClosureType: (newClosureType: ClosureType) => void; -} - -const ClosureOptionsComponent: React.FC = ({ - closureTypeSelected, - disabled, - onChangeClosureType, -}) => { - return ( - {i18n.CASE_CLOSURE_OPTIONS_TITLE}} - description={ - <> -

{i18n.CASE_CLOSURE_OPTIONS_DESC}

-

{i18n.CASE_COLSURE_OPTIONS_SUB_CASES}

- - } - data-test-subj="case-closure-options-form-group" - > - - - -
- ); -}; - -export const ClosureOptions = React.memo(ClosureOptionsComponent); diff --git a/x-pack/plugins/cases/public/components/configure_cases/closure_options_radio.test.tsx b/x-pack/plugins/cases/public/components/configure_cases/closure_options_radio.test.tsx deleted file mode 100644 index b9885b4e07d4..000000000000 --- a/x-pack/plugins/cases/public/components/configure_cases/closure_options_radio.test.tsx +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { ReactWrapper, mount } from 'enzyme'; - -import { ClosureOptionsRadio, ClosureOptionsRadioComponentProps } from './closure_options_radio'; -import { TestProviders } from '../../common/mock'; - -describe('ClosureOptionsRadio', () => { - let wrapper: ReactWrapper; - const onChangeClosureType = jest.fn(); - const props: ClosureOptionsRadioComponentProps = { - disabled: false, - closureTypeSelected: 'close-by-user', - onChangeClosureType, - }; - - beforeAll(() => { - wrapper = mount(, { wrappingComponent: TestProviders }); - }); - - test('it renders', () => { - expect(wrapper.find('[data-test-subj="closure-options-radio-group"]').first().exists()).toBe( - true - ); - }); - - test('it shows the correct number of radio buttons', () => { - expect(wrapper.find('input[name="closure_options"]')).toHaveLength(2); - }); - - test('it renders close by user radio button', () => { - expect(wrapper.find('input[id="close-by-user"]').exists()).toBeTruthy(); - }); - - test('it renders close by pushing radio button', () => { - expect(wrapper.find('input[id="close-by-pushing"]').exists()).toBeTruthy(); - }); - - test('it disables the close by user radio button', () => { - const newWrapper = mount(, { - wrappingComponent: TestProviders, - }); - - expect(newWrapper.find('input[id="close-by-user"]').prop('disabled')).toEqual(true); - }); - - test('it disables correctly the close by pushing radio button', () => { - const newWrapper = mount(, { - wrappingComponent: TestProviders, - }); - - expect(newWrapper.find('input[id="close-by-pushing"]').prop('disabled')).toEqual(true); - }); - - test('it selects the correct radio button', () => { - const newWrapper = mount( - , - { - wrappingComponent: TestProviders, - } - ); - expect(newWrapper.find('input[id="close-by-pushing"]').prop('checked')).toEqual(true); - }); - - test('it calls the onChangeClosureType function', () => { - wrapper.find('input[id="close-by-pushing"]').simulate('change'); - wrapper.update(); - expect(onChangeClosureType).toHaveBeenCalled(); - expect(onChangeClosureType).toHaveBeenCalledWith('close-by-pushing'); - }); -}); diff --git a/x-pack/plugins/cases/public/components/configure_cases/closure_options_radio.tsx b/x-pack/plugins/cases/public/components/configure_cases/closure_options_radio.tsx deleted file mode 100644 index cb6fa0953a79..000000000000 --- a/x-pack/plugins/cases/public/components/configure_cases/closure_options_radio.tsx +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { ReactNode, useCallback } from 'react'; -import { EuiRadioGroup } from '@elastic/eui'; - -import { ClosureType } from '../../containers/configure/types'; -import * as i18n from './translations'; - -interface ClosureRadios { - id: ClosureType; - label: ReactNode; -} - -const radios: ClosureRadios[] = [ - { - id: 'close-by-user', - label: i18n.CASE_CLOSURE_OPTIONS_MANUAL, - }, - { - id: 'close-by-pushing', - label: i18n.CASE_CLOSURE_OPTIONS_NEW_INCIDENT, - }, -]; - -export interface ClosureOptionsRadioComponentProps { - closureTypeSelected: ClosureType; - disabled: boolean; - onChangeClosureType: (newClosureType: ClosureType) => void; -} - -const ClosureOptionsRadioComponent: React.FC = ({ - closureTypeSelected, - disabled, - onChangeClosureType, -}) => { - const onChangeLocal = useCallback( - (id: string) => { - onChangeClosureType(id as ClosureType); - }, - [onChangeClosureType] - ); - - return ( - - ); -}; - -export const ClosureOptionsRadio = React.memo(ClosureOptionsRadioComponent); diff --git a/x-pack/plugins/cases/public/components/configure_cases/connectors.test.tsx b/x-pack/plugins/cases/public/components/configure_cases/connectors.test.tsx deleted file mode 100644 index d5b9a885f2c6..000000000000 --- a/x-pack/plugins/cases/public/components/configure_cases/connectors.test.tsx +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { mount, ReactWrapper } from 'enzyme'; - -import { Connectors, Props } from './connectors'; -import { TestProviders } from '../../common/mock'; -import { ConnectorsDropdown } from './connectors_dropdown'; -import { connectors } from './__mock__'; -import { ConnectorTypes } from '../../../common'; - -describe('Connectors', () => { - let wrapper: ReactWrapper; - const onChangeConnector = jest.fn(); - const handleShowEditFlyout = jest.fn(); - - const props: Props = { - connectors, - disabled: false, - handleShowEditFlyout, - isLoading: false, - mappings: [], - onChangeConnector, - selectedConnector: { id: 'none', type: ConnectorTypes.none }, - updateConnectorDisabled: false, - }; - - beforeAll(() => { - wrapper = mount(, { wrappingComponent: TestProviders }); - }); - - test('it shows the connectors from group', () => { - expect(wrapper.find('[data-test-subj="case-connectors-form-group"]').first().exists()).toBe( - true - ); - }); - - test('it shows the connectors form row', () => { - expect(wrapper.find('[data-test-subj="case-connectors-form-row"]').first().exists()).toBe(true); - }); - - test('it shows the connectors dropdown', () => { - expect(wrapper.find('[data-test-subj="case-connectors-dropdown"]').first().exists()).toBe(true); - }); - - test('it pass the correct props to child', () => { - const connectorsDropdownProps = wrapper.find(ConnectorsDropdown).props(); - expect(connectorsDropdownProps).toMatchObject({ - disabled: false, - isLoading: false, - connectors, - selectedConnector: 'none', - onChange: props.onChangeConnector, - }); - }); - - test('the connector is changed successfully', () => { - wrapper.find('button[data-test-subj="dropdown-connectors"]').simulate('click'); - wrapper.find('button[data-test-subj="dropdown-connector-resilient-2"]').simulate('click'); - - expect(onChangeConnector).toHaveBeenCalled(); - expect(onChangeConnector).toHaveBeenCalledWith('resilient-2'); - }); - - test('the connector is changed successfully to none', () => { - onChangeConnector.mockClear(); - const newWrapper = mount( - , - { - wrappingComponent: TestProviders, - } - ); - - newWrapper.find('button[data-test-subj="dropdown-connectors"]').simulate('click'); - newWrapper.find('button[data-test-subj="dropdown-connector-no-connector"]').simulate('click'); - - expect(onChangeConnector).toHaveBeenCalled(); - expect(onChangeConnector).toHaveBeenCalledWith('none'); - }); - - test('it shows the add connector button', () => { - wrapper.find('button[data-test-subj="dropdown-connectors"]').simulate('click'); - wrapper.update(); - - expect( - wrapper.find('button[data-test-subj="dropdown-connector-add-connector"]').exists() - ).toBeTruthy(); - }); - - test('the text of the update button is shown correctly', () => { - const newWrapper = mount( - , - { - wrappingComponent: TestProviders, - } - ); - - expect( - newWrapper - .find('button[data-test-subj="case-configure-update-selected-connector-button"]') - .text() - ).toBe('Update My Connector'); - }); -}); diff --git a/x-pack/plugins/cases/public/components/configure_cases/connectors.tsx b/x-pack/plugins/cases/public/components/configure_cases/connectors.tsx deleted file mode 100644 index 45be02e05e1f..000000000000 --- a/x-pack/plugins/cases/public/components/configure_cases/connectors.tsx +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { useMemo } from 'react'; -import { - EuiDescribedFormGroup, - EuiFormRow, - EuiFlexGroup, - EuiFlexItem, - EuiLink, -} from '@elastic/eui'; - -import styled from 'styled-components'; - -import { ConnectorsDropdown } from './connectors_dropdown'; -import * as i18n from './translations'; - -import { ActionConnector, CaseConnectorMapping } from '../../containers/configure/types'; -import { Mapping } from './mapping'; -import { ConnectorTypes } from '../../../common'; - -const EuiFormRowExtended = styled(EuiFormRow)` - .euiFormRow__labelWrapper { - .euiFormRow__label { - width: 100%; - } - } -`; - -export interface Props { - connectors: ActionConnector[]; - disabled: boolean; - handleShowEditFlyout: () => void; - isLoading: boolean; - mappings: CaseConnectorMapping[]; - onChangeConnector: (id: string) => void; - selectedConnector: { id: string; type: string }; - updateConnectorDisabled: boolean; -} -const ConnectorsComponent: React.FC = ({ - connectors, - disabled, - handleShowEditFlyout, - isLoading, - mappings, - onChangeConnector, - selectedConnector, - updateConnectorDisabled, -}) => { - const connectorsName = useMemo( - () => connectors.find((c) => c.id === selectedConnector.id)?.name ?? 'none', - [connectors, selectedConnector.id] - ); - - const dropDownLabel = useMemo( - () => ( - - {i18n.INCIDENT_MANAGEMENT_SYSTEM_LABEL} - - {connectorsName !== 'none' && ( - - {i18n.UPDATE_SELECTED_CONNECTOR(connectorsName)} - - )} - - - ), - [connectorsName, handleShowEditFlyout, updateConnectorDisabled] - ); - return ( - <> - {i18n.INCIDENT_MANAGEMENT_SYSTEM_TITLE}} - description={i18n.INCIDENT_MANAGEMENT_SYSTEM_DESC} - data-test-subj="case-connectors-form-group" - > - - - - - - {selectedConnector.type !== ConnectorTypes.none ? ( - - - - ) : null} - - - - - ); -}; - -export const Connectors = React.memo(ConnectorsComponent); diff --git a/x-pack/plugins/cases/public/components/configure_cases/connectors_dropdown.test.tsx b/x-pack/plugins/cases/public/components/configure_cases/connectors_dropdown.test.tsx deleted file mode 100644 index 5149052d9a4b..000000000000 --- a/x-pack/plugins/cases/public/components/configure_cases/connectors_dropdown.test.tsx +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { mount, ReactWrapper } from 'enzyme'; -import { EuiSuperSelect } from '@elastic/eui'; - -import { ConnectorsDropdown, Props } from './connectors_dropdown'; -import { TestProviders } from '../../common/mock'; -import { connectors } from './__mock__'; - -describe('ConnectorsDropdown', () => { - let wrapper: ReactWrapper; - const props: Props = { - disabled: false, - connectors, - isLoading: false, - onChange: jest.fn(), - selectedConnector: 'none', - }; - - beforeAll(() => { - wrapper = mount(, { wrappingComponent: TestProviders }); - }); - - test('it renders', () => { - expect(wrapper.find('[data-test-subj="dropdown-connectors"]').first().exists()).toBe(true); - }); - - test('it formats the connectors correctly', () => { - const selectProps = wrapper.find(EuiSuperSelect).props(); - - expect(selectProps.options).toMatchInlineSnapshot(` - Array [ - Object { - "data-test-subj": "dropdown-connector-no-connector", - "inputDisplay": - - - - - - No connector selected - - - , - "value": "none", - }, - Object { - "data-test-subj": "dropdown-connector-servicenow-1", - "inputDisplay": - - - - - - My Connector - - - , - "value": "servicenow-1", - }, - Object { - "data-test-subj": "dropdown-connector-resilient-2", - "inputDisplay": - - - - - - My Connector 2 - - - , - "value": "resilient-2", - }, - Object { - "data-test-subj": "dropdown-connector-jira-1", - "inputDisplay": - - - - - - Jira - - - , - "value": "jira-1", - }, - Object { - "data-test-subj": "dropdown-connector-servicenow-sir", - "inputDisplay": - - - - - - My Connector SIR - - - , - "value": "servicenow-sir", - }, - ] - `); - }); - - test('it disables the dropdown', () => { - const newWrapper = mount(, { - wrappingComponent: TestProviders, - }); - - expect( - newWrapper.find('[data-test-subj="dropdown-connectors"]').first().prop('disabled') - ).toEqual(true); - }); - - test('it loading correctly', () => { - const newWrapper = mount(, { - wrappingComponent: TestProviders, - }); - - expect( - newWrapper.find('[data-test-subj="dropdown-connectors"]').first().prop('isLoading') - ).toEqual(true); - }); - - test('it selects the correct connector', () => { - const newWrapper = mount(, { - wrappingComponent: TestProviders, - }); - - expect(newWrapper.find('button span:not([data-euiicon-type])').text()).toEqual('My Connector'); - }); - - test('if the props hideConnectorServiceNowSir is true, the connector should not be part of the list of options ', () => { - const newWrapper = mount( - , - { - wrappingComponent: TestProviders, - } - ); - const selectProps = newWrapper.find(EuiSuperSelect).props(); - const options = selectProps.options as Array<{ 'data-test-subj': string }>; - expect( - options.some((o) => o['data-test-subj'] === 'dropdown-connector-servicenow-1') - ).toBeTruthy(); - expect( - options.some((o) => o['data-test-subj'] === 'dropdown-connector-servicenow-sir') - ).toBeFalsy(); - }); -}); diff --git a/x-pack/plugins/cases/public/components/configure_cases/connectors_dropdown.tsx b/x-pack/plugins/cases/public/components/configure_cases/connectors_dropdown.tsx deleted file mode 100644 index 21ef5c490b17..000000000000 --- a/x-pack/plugins/cases/public/components/configure_cases/connectors_dropdown.tsx +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { useMemo } from 'react'; -import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiSuperSelect } from '@elastic/eui'; -import styled from 'styled-components'; - -import { ConnectorTypes } from '../../../common'; -import { ActionConnector } from '../../containers/configure/types'; -import { connectorsConfiguration } from '../connectors'; -import * as i18n from './translations'; - -export interface Props { - connectors: ActionConnector[]; - disabled: boolean; - isLoading: boolean; - onChange: (id: string) => void; - selectedConnector: string; - appendAddConnectorButton?: boolean; - hideConnectorServiceNowSir?: boolean; -} - -const ICON_SIZE = 'm'; - -const EuiIconExtended = styled(EuiIcon)` - margin-right: 13px; - margin-bottom: 0 !important; -`; - -const noConnectorOption = { - value: 'none', - inputDisplay: ( - - - - - - {i18n.NO_CONNECTOR} - - - ), - 'data-test-subj': 'dropdown-connector-no-connector', -}; - -const addNewConnector = { - value: 'add-connector', - inputDisplay: ( - - {i18n.ADD_NEW_CONNECTOR} - - ), - 'data-test-subj': 'dropdown-connector-add-connector', -}; - -const ConnectorsDropdownComponent: React.FC = ({ - connectors, - disabled, - isLoading, - onChange, - selectedConnector, - appendAddConnectorButton = false, - hideConnectorServiceNowSir = false, -}) => { - const connectorsAsOptions = useMemo(() => { - const connectorsFormatted = connectors.reduce( - (acc, connector) => { - if (hideConnectorServiceNowSir && connector.actionTypeId === ConnectorTypes.serviceNowSIR) { - return acc; - } - - return [ - ...acc, - { - value: connector.id, - inputDisplay: ( - - - - - - {connector.name} - - - ), - 'data-test-subj': `dropdown-connector-${connector.id}`, - }, - ]; - }, - [noConnectorOption] - ); - - if (appendAddConnectorButton) { - return [...connectorsFormatted, addNewConnector]; - } - - return connectorsFormatted; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [connectors]); - - return ( - - ); -}; - -export const ConnectorsDropdown = React.memo(ConnectorsDropdownComponent); diff --git a/x-pack/plugins/cases/public/components/configure_cases/field_mapping.test.tsx b/x-pack/plugins/cases/public/components/configure_cases/field_mapping.test.tsx deleted file mode 100644 index 8c2a66ad7ee5..000000000000 --- a/x-pack/plugins/cases/public/components/configure_cases/field_mapping.test.tsx +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { mount, ReactWrapper } from 'enzyme'; - -import { FieldMapping, FieldMappingProps } from './field_mapping'; -import { mappings } from './__mock__'; -import { TestProviders } from '../../common/mock'; -import { FieldMappingRowStatic } from './field_mapping_row_static'; - -describe('FieldMappingRow', () => { - let wrapper: ReactWrapper; - const props: FieldMappingProps = { - isLoading: false, - mappings, - connectorActionTypeId: '.servicenow', - }; - - beforeAll(() => { - wrapper = mount(, { wrappingComponent: TestProviders }); - }); - test('it renders', () => { - expect( - wrapper.find('[data-test-subj="case-configure-field-mappings-row-wrapper"]').first().exists() - ).toBe(true); - - expect(wrapper.find(FieldMappingRowStatic).length).toEqual(3); - }); - - test('it does not render without mappings', () => { - const newWrapper = mount(, { - wrappingComponent: TestProviders, - }); - expect( - newWrapper - .find('[data-test-subj="case-configure-field-mappings-row-wrapper"]') - .first() - .exists() - ).toBe(false); - }); - - test('it pass the corrects props to mapping row', () => { - const rows = wrapper.find(FieldMappingRowStatic); - rows.forEach((row, index) => { - expect(row.prop('casesField')).toEqual(mappings[index].source); - expect(row.prop('selectedActionType')).toEqual(mappings[index].actionType); - expect(row.prop('selectedThirdParty')).toEqual(mappings[index].target); - }); - }); -}); diff --git a/x-pack/plugins/cases/public/components/configure_cases/field_mapping.tsx b/x-pack/plugins/cases/public/components/configure_cases/field_mapping.tsx deleted file mode 100644 index ef7e8ecda0c8..000000000000 --- a/x-pack/plugins/cases/public/components/configure_cases/field_mapping.tsx +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { useMemo } from 'react'; -import { EuiFlexItem, EuiFlexGroup } from '@elastic/eui'; -import styled from 'styled-components'; - -import { FieldMappingRowStatic } from './field_mapping_row_static'; -import * as i18n from './translations'; - -import { CaseConnectorMapping } from '../../containers/configure/types'; -import { connectorsConfiguration } from '../connectors'; - -const FieldRowWrapper = styled.div` - margin: 10px 0; - font-size: 14px; -`; - -export interface FieldMappingProps { - connectorActionTypeId: string; - isLoading: boolean; - mappings: CaseConnectorMapping[]; -} - -const FieldMappingComponent: React.FC = ({ - connectorActionTypeId, - isLoading, - mappings, -}) => { - const selectedConnector = useMemo( - () => connectorsConfiguration[connectorActionTypeId] ?? { fields: {} }, - [connectorActionTypeId] - ); - return mappings.length ? ( - - - {' '} - - - {i18n.FIELD_MAPPING_FIRST_COL} - - - - {i18n.FIELD_MAPPING_SECOND_COL(selectedConnector.name)} - - - - {i18n.FIELD_MAPPING_THIRD_COL} - - - - - - {mappings.map((item) => ( - - ))} - - - - ) : null; -}; - -export const FieldMapping = React.memo(FieldMappingComponent); diff --git a/x-pack/plugins/cases/public/components/configure_cases/field_mapping_row_static.tsx b/x-pack/plugins/cases/public/components/configure_cases/field_mapping_row_static.tsx deleted file mode 100644 index 52672197ecb5..000000000000 --- a/x-pack/plugins/cases/public/components/configure_cases/field_mapping_row_static.tsx +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { useMemo } from 'react'; -import { EuiCode, EuiFlexItem, EuiFlexGroup, EuiIcon, EuiLoadingSpinner } from '@elastic/eui'; - -import { capitalize } from 'lodash/fp'; -import { CaseField, ActionType, ThirdPartyField } from '../../containers/configure/types'; - -export interface RowProps { - isLoading: boolean; - casesField: CaseField; - selectedActionType: ActionType; - selectedThirdParty: ThirdPartyField; -} - -const FieldMappingRowComponent: React.FC = ({ - isLoading, - casesField, - selectedActionType, - selectedThirdParty, -}) => { - const selectedActionTypeCapitalized = useMemo(() => capitalize(selectedActionType), [ - selectedActionType, - ]); - return ( - - - - - {casesField} - - - - - - - - - - {isLoading ? ( - - ) : ( - {selectedThirdParty} - )} - - - - - {isLoading ? : selectedActionTypeCapitalized} - - - ); -}; - -export const FieldMappingRowStatic = React.memo(FieldMappingRowComponent); diff --git a/x-pack/plugins/cases/public/components/configure_cases/index.test.tsx b/x-pack/plugins/cases/public/components/configure_cases/index.test.tsx deleted file mode 100644 index 898d6cde19a7..000000000000 --- a/x-pack/plugins/cases/public/components/configure_cases/index.test.tsx +++ /dev/null @@ -1,591 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { ReactWrapper, mount } from 'enzyme'; - -import { ConfigureCases } from '.'; -import { TestProviders } from '../../common/mock'; -import { Connectors } from './connectors'; -import { ClosureOptions } from './closure_options'; -import { - ActionConnector, - ConnectorAddFlyout, - ConnectorEditFlyout, - TriggersAndActionsUIPublicPluginStart, -} from '../../../../triggers_actions_ui/public'; -import { actionTypeRegistryMock } from '../../../../triggers_actions_ui/public/application/action_type_registry.mock'; - -import { useKibana } from '../../common/lib/kibana'; -import { useConnectors } from '../../containers/configure/use_connectors'; -import { useCaseConfigure } from '../../containers/configure/use_configure'; -import { useActionTypes } from '../../containers/configure/use_action_types'; - -import { - connectors, - searchURL, - useCaseConfigureResponse, - useConnectorsResponse, - useActionTypesResponse, -} from './__mock__'; -import { ConnectorTypes } from '../../../common'; - -jest.mock('../../common/lib/kibana'); -jest.mock('../../containers/configure/use_connectors'); -jest.mock('../../containers/configure/use_configure'); -jest.mock('../../containers/configure/use_action_types'); - -const useKibanaMock = useKibana as jest.Mocked; -const useConnectorsMock = useConnectors as jest.Mock; -const useCaseConfigureMock = useCaseConfigure as jest.Mock; -const useGetUrlSearchMock = jest.fn(); -const useActionTypesMock = useActionTypes as jest.Mock; - -describe('ConfigureCases', () => { - beforeEach(() => { - useKibanaMock().services.triggersActionsUi = ({ - actionTypeRegistry: actionTypeRegistryMock.create(), - getAddConnectorFlyout: jest.fn().mockImplementation(() => ( - {}} - actionTypeRegistry={actionTypeRegistryMock.create()} - actionTypes={[ - { - id: '.servicenow', - name: 'servicenow', - enabled: true, - enabledInConfig: true, - enabledInLicense: true, - minimumLicenseRequired: 'gold', - }, - { - id: '.jira', - name: 'jira', - enabled: true, - enabledInConfig: true, - enabledInLicense: true, - minimumLicenseRequired: 'gold', - }, - { - id: '.resilient', - name: 'resilient', - enabled: true, - enabledInConfig: true, - enabledInLicense: true, - minimumLicenseRequired: 'gold', - }, - ]} - /> - )), - getEditConnectorFlyout: jest - .fn() - .mockImplementation(() => ( - {}} - actionTypeRegistry={actionTypeRegistryMock.create()} - initialConnector={connectors[1] as ActionConnector} - /> - )), - } as unknown) as TriggersAndActionsUIPublicPluginStart; - - useActionTypesMock.mockImplementation(() => useActionTypesResponse); - }); - - describe('rendering', () => { - let wrapper: ReactWrapper; - beforeEach(() => { - useCaseConfigureMock.mockImplementation(() => useCaseConfigureResponse); - useConnectorsMock.mockImplementation(() => ({ ...useConnectorsResponse, connectors: [] })); - useGetUrlSearchMock.mockImplementation(() => searchURL); - - wrapper = mount(, { wrappingComponent: TestProviders }); - }); - - test('it renders the Connectors', () => { - expect(wrapper.find('[data-test-subj="dropdown-connectors"]').exists()).toBeTruthy(); - }); - - test('it renders the ClosureType', () => { - expect(wrapper.find('[data-test-subj="closure-options-radio-group"]').exists()).toBeTruthy(); - }); - - test('it does NOT render the ConnectorAddFlyout', () => { - // Components from triggersActionsUi do not have a data-test-subj - expect(wrapper.find(ConnectorAddFlyout).exists()).toBeFalsy(); - }); - - test('it does NOT render the ConnectorEditFlyout', () => { - // Components from triggersActionsUi do not have a data-test-subj - expect(wrapper.find(ConnectorEditFlyout).exists()).toBeFalsy(); - }); - - test('it does NOT render the EuiCallOut', () => { - expect( - wrapper.find('[data-test-subj="configure-cases-warning-callout"]').exists() - ).toBeFalsy(); - }); - }); - - describe('Unhappy path', () => { - let wrapper: ReactWrapper; - - beforeEach(() => { - useCaseConfigureMock.mockImplementation(() => ({ - ...useCaseConfigureResponse, - closureType: 'close-by-user', - connector: { - id: 'not-id', - name: 'unchanged', - type: ConnectorTypes.none, - fields: null, - }, - currentConfiguration: { - connector: { - id: 'not-id', - name: 'unchanged', - type: ConnectorTypes.none, - fields: null, - }, - closureType: 'close-by-user', - }, - })); - useConnectorsMock.mockImplementation(() => ({ ...useConnectorsResponse, connectors: [] })); - useGetUrlSearchMock.mockImplementation(() => searchURL); - wrapper = mount(, { wrappingComponent: TestProviders }); - }); - - test('it shows the warning callout when configuration is invalid', () => { - expect( - wrapper.find('[data-test-subj="configure-cases-warning-callout"]').exists() - ).toBeTruthy(); - }); - - test('it hides the update connector button when the connectorId is invalid', () => { - expect( - wrapper - .find('button[data-test-subj="case-configure-update-selected-connector-button"]') - .exists() - ).toBeFalsy(); - }); - }); - - describe('Happy path', () => { - let wrapper: ReactWrapper; - - beforeEach(() => { - useCaseConfigureMock.mockImplementation(() => ({ - ...useCaseConfigureResponse, - mappings: [], - closureType: 'close-by-user', - connector: { - id: 'servicenow-1', - name: 'unchanged', - type: ConnectorTypes.serviceNowITSM, - fields: null, - }, - currentConfiguration: { - connector: { - id: 'servicenow-1', - name: 'unchanged', - type: ConnectorTypes.serviceNowITSM, - fields: null, - }, - closureType: 'close-by-user', - }, - })); - useConnectorsMock.mockImplementation(() => useConnectorsResponse); - useGetUrlSearchMock.mockImplementation(() => searchURL); - - wrapper = mount(, { wrappingComponent: TestProviders }); - }); - - test('it renders with correct props', () => { - // Connector - expect(wrapper.find(Connectors).prop('connectors')).toEqual(connectors); - expect(wrapper.find(Connectors).prop('disabled')).toBe(false); - expect(wrapper.find(Connectors).prop('isLoading')).toBe(false); - expect(wrapper.find(Connectors).prop('selectedConnector').id).toBe('servicenow-1'); - - // ClosureOptions - expect(wrapper.find(ClosureOptions).prop('disabled')).toBe(false); - expect(wrapper.find(ClosureOptions).prop('closureTypeSelected')).toBe('close-by-user'); - - // Flyouts - expect(wrapper.find(ConnectorAddFlyout).exists()).toBe(false); - expect(wrapper.find(ConnectorEditFlyout).exists()).toBe(false); - }); - - test('it disables correctly when the user cannot crud', () => { - const newWrapper = mount(, { - wrappingComponent: TestProviders, - }); - - expect(newWrapper.find('button[data-test-subj="dropdown-connectors"]').prop('disabled')).toBe( - true - ); - - expect( - newWrapper - .find('button[data-test-subj="case-configure-update-selected-connector-button"]') - .prop('disabled') - ).toBe(true); - - // Two closure options - expect( - newWrapper - .find('[data-test-subj="closure-options-radio-group"] input') - .first() - .prop('disabled') - ).toBe(true); - - expect( - newWrapper - .find('[data-test-subj="closure-options-radio-group"] input') - .at(1) - .prop('disabled') - ).toBe(true); - }); - }); - - describe('loading connectors', () => { - let wrapper: ReactWrapper; - - beforeEach(() => { - useCaseConfigureMock.mockImplementation(() => ({ - ...useCaseConfigureResponse, - mapping: null, - closureType: 'close-by-user', - connector: { - id: 'resilient-2', - name: 'unchanged', - type: ConnectorTypes.resilient, - fields: null, - }, - currentConfiguration: { - connector: { - id: 'servicenow-1', - name: 'unchanged', - type: ConnectorTypes.serviceNowITSM, - fields: null, - }, - closureType: 'close-by-user', - }, - })); - - useConnectorsMock.mockImplementation(() => ({ - ...useConnectorsResponse, - loading: true, - })); - - useGetUrlSearchMock.mockImplementation(() => searchURL); - wrapper = mount(, { wrappingComponent: TestProviders }); - }); - - test('it disables correctly Connector when loading connectors', () => { - expect( - wrapper.find('button[data-test-subj="dropdown-connectors"]').prop('disabled') - ).toBeTruthy(); - }); - - test('it pass the correct value to isLoading attribute on Connector', () => { - expect(wrapper.find(Connectors).prop('isLoading')).toBe(true); - }); - - test('it disables correctly ClosureOptions when loading connectors', () => { - expect(wrapper.find(ClosureOptions).prop('disabled')).toBe(true); - }); - - test('it hides the update connector button when loading the connectors', () => { - expect( - wrapper - .find('button[data-test-subj="case-configure-update-selected-connector-button"]') - .prop('disabled') - ).toBe(true); - }); - - test('it shows isLoading when loading action types', () => { - useConnectorsMock.mockImplementation(() => ({ - ...useConnectorsResponse, - loading: false, - })); - - useActionTypesMock.mockImplementation(() => ({ ...useActionTypesResponse, loading: true })); - - wrapper = mount(, { wrappingComponent: TestProviders }); - expect(wrapper.find(Connectors).prop('isLoading')).toBe(true); - }); - }); - - describe('saving configuration', () => { - let wrapper: ReactWrapper; - - beforeEach(() => { - useCaseConfigureMock.mockImplementation(() => ({ - ...useCaseConfigureResponse, - connector: { - id: 'servicenow-1', - name: 'SN', - type: ConnectorTypes.serviceNowITSM, - fields: null, - }, - persistLoading: true, - })); - - useConnectorsMock.mockImplementation(() => useConnectorsResponse); - useGetUrlSearchMock.mockImplementation(() => searchURL); - wrapper = mount(, { wrappingComponent: TestProviders }); - }); - - test('it disables correctly Connector when saving configuration', () => { - expect(wrapper.find(Connectors).prop('disabled')).toBe(true); - }); - - test('it disables correctly ClosureOptions when saving configuration', () => { - expect( - wrapper - .find('[data-test-subj="closure-options-radio-group"] input') - .first() - .prop('disabled') - ).toBe(true); - - expect( - wrapper.find('[data-test-subj="closure-options-radio-group"] input').at(1).prop('disabled') - ).toBe(true); - }); - - test('it disables the update connector button when saving the configuration', () => { - expect( - wrapper - .find('button[data-test-subj="case-configure-update-selected-connector-button"]') - .prop('disabled') - ).toBe(true); - }); - }); - - describe('loading configuration', () => { - let wrapper: ReactWrapper; - - beforeEach(() => { - useCaseConfigureMock.mockImplementation(() => ({ - ...useCaseConfigureResponse, - loading: true, - })); - useConnectorsMock.mockImplementation(() => ({ - ...useConnectorsResponse, - })); - useGetUrlSearchMock.mockImplementation(() => searchURL); - wrapper = mount(, { wrappingComponent: TestProviders }); - }); - - test('it hides the update connector button when loading the configuration', () => { - expect( - wrapper - .find('button[data-test-subj="case-configure-update-selected-connector-button"]') - .exists() - ).toBeFalsy(); - }); - }); - - describe('connectors', () => { - let wrapper: ReactWrapper; - let persistCaseConfigure: jest.Mock; - - beforeEach(() => { - persistCaseConfigure = jest.fn(); - useCaseConfigureMock.mockImplementation(() => ({ - ...useCaseConfigureResponse, - mapping: null, - closureType: 'close-by-user', - connector: { - id: 'resilient-2', - name: 'My connector', - type: ConnectorTypes.resilient, - fields: null, - }, - currentConfiguration: { - connector: { - id: 'My connector', - name: 'My connector', - type: ConnectorTypes.jira, - fields: null, - }, - closureType: 'close-by-user', - }, - persistCaseConfigure, - })); - useConnectorsMock.mockImplementation(() => useConnectorsResponse); - useGetUrlSearchMock.mockImplementation(() => searchURL); - - wrapper = mount(, { wrappingComponent: TestProviders }); - }); - - test('it submits the configuration correctly when changing connector', () => { - wrapper.find('button[data-test-subj="dropdown-connectors"]').simulate('click'); - wrapper.update(); - wrapper.find('button[data-test-subj="dropdown-connector-resilient-2"]').simulate('click'); - wrapper.update(); - - expect(persistCaseConfigure).toHaveBeenCalled(); - expect(persistCaseConfigure).toHaveBeenCalledWith({ - connector: { - id: 'resilient-2', - name: 'My Connector 2', - type: ConnectorTypes.resilient, - fields: null, - }, - closureType: 'close-by-user', - }); - }); - - test('the text of the update button is changed successfully', () => { - useCaseConfigureMock - .mockImplementationOnce(() => ({ - ...useCaseConfigureResponse, - connector: { - id: 'servicenow-1', - name: 'My connector', - type: ConnectorTypes.serviceNowITSM, - fields: null, - }, - })) - .mockImplementation(() => ({ - ...useCaseConfigureResponse, - connector: { - id: 'resilient-2', - name: 'My connector 2', - type: ConnectorTypes.resilient, - fields: null, - }, - })); - - wrapper = mount(, { wrappingComponent: TestProviders }); - - wrapper.find('button[data-test-subj="dropdown-connectors"]').simulate('click'); - wrapper.update(); - wrapper.find('button[data-test-subj="dropdown-connector-resilient-2"]').simulate('click'); - wrapper.update(); - - expect( - wrapper - .find('button[data-test-subj="case-configure-update-selected-connector-button"]') - .text() - ).toBe('Update My Connector 2'); - }); - }); -}); - -describe('closure options', () => { - let wrapper: ReactWrapper; - let persistCaseConfigure: jest.Mock; - - beforeEach(() => { - persistCaseConfigure = jest.fn(); - useCaseConfigureMock.mockImplementation(() => ({ - ...useCaseConfigureResponse, - mapping: null, - closureType: 'close-by-user', - connector: { - id: 'servicenow-1', - name: 'My connector', - type: ConnectorTypes.serviceNowITSM, - fields: null, - }, - currentConfiguration: { - connector: { - id: 'My connector', - name: 'My connector', - type: ConnectorTypes.jira, - fields: null, - }, - closureType: 'close-by-user', - }, - persistCaseConfigure, - })); - useConnectorsMock.mockImplementation(() => useConnectorsResponse); - useGetUrlSearchMock.mockImplementation(() => searchURL); - - wrapper = mount(, { wrappingComponent: TestProviders }); - }); - - test('it submits the configuration correctly when changing closure type', () => { - wrapper.find('input[id="close-by-pushing"]').simulate('change'); - wrapper.update(); - - expect(persistCaseConfigure).toHaveBeenCalled(); - expect(persistCaseConfigure).toHaveBeenCalledWith({ - connector: { - id: 'servicenow-1', - name: 'My connector', - type: ConnectorTypes.serviceNowITSM, - fields: null, - }, - closureType: 'close-by-pushing', - }); - }); -}); - -describe('user interactions', () => { - beforeEach(() => { - useCaseConfigureMock.mockImplementation(() => ({ - ...useCaseConfigureResponse, - mapping: null, - closureType: 'close-by-user', - connector: { - id: 'resilient-2', - name: 'unchanged', - type: ConnectorTypes.resilient, - fields: null, - }, - currentConfiguration: { - connector: { - id: 'resilient-2', - name: 'unchanged', - type: ConnectorTypes.serviceNowITSM, - fields: null, - }, - closureType: 'close-by-user', - }, - })); - useConnectorsMock.mockImplementation(() => useConnectorsResponse); - useGetUrlSearchMock.mockImplementation(() => searchURL); - }); - - test('it show the add flyout when pressing the add connector button', () => { - const wrapper = mount(, { wrappingComponent: TestProviders }); - wrapper.find('button[data-test-subj="dropdown-connectors"]').simulate('click'); - wrapper.update(); - wrapper.find('button[data-test-subj="dropdown-connector-add-connector"]').simulate('click'); - wrapper.update(); - - expect(wrapper.find(ConnectorAddFlyout).exists()).toBe(true); - expect(wrapper.find(ConnectorAddFlyout).prop('actionTypes')).toEqual([ - expect.objectContaining({ - id: '.servicenow', - }), - expect.objectContaining({ - id: '.jira', - }), - expect.objectContaining({ - id: '.resilient', - }), - ]); - }); - - test('it show the edit flyout when pressing the update connector button', () => { - const wrapper = mount(, { wrappingComponent: TestProviders }); - wrapper - .find('button[data-test-subj="case-configure-update-selected-connector-button"]') - .simulate('click'); - wrapper.update(); - - expect(wrapper.find(ConnectorEditFlyout).exists()).toBe(true); - expect(wrapper.find(ConnectorEditFlyout).prop('initialConnector')).toEqual(connectors[1]); - expect( - wrapper.find('[data-test-subj="case-configure-action-bottom-bar"]').exists() - ).toBeFalsy(); - }); -}); diff --git a/x-pack/plugins/cases/public/components/configure_cases/index.tsx b/x-pack/plugins/cases/public/components/configure_cases/index.tsx deleted file mode 100644 index 3e352f119e84..000000000000 --- a/x-pack/plugins/cases/public/components/configure_cases/index.tsx +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { useCallback, useEffect, useMemo, useState } from 'react'; -import styled, { css } from 'styled-components'; - -import { EuiCallOut } from '@elastic/eui'; - -import { SUPPORTED_CONNECTORS } from '../../../common'; -import { useKibana } from '../../common/lib/kibana'; -import { useConnectors } from '../../containers/configure/use_connectors'; -import { useActionTypes } from '../../containers/configure/use_action_types'; -import { useCaseConfigure } from '../../containers/configure/use_configure'; - -import { ClosureType } from '../../containers/configure/types'; - -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { ActionConnectorTableItem } from '../../../../triggers_actions_ui/public/types'; - -import { SectionWrapper } from '../wrappers'; -import { Connectors } from './connectors'; -import { ClosureOptions } from './closure_options'; -import { - getConnectorById, - getNoneConnector, - normalizeActionConnector, - normalizeCaseConnector, -} from './utils'; -import * as i18n from './translations'; - -const FormWrapper = styled.div` - ${({ theme }) => css` - & > * { - margin-top 40px; - } - - & > :first-child { - margin-top: 0; - } - - padding-top: ${theme.eui.paddingSizes.xl}; - padding-bottom: ${theme.eui.paddingSizes.xl}; - .euiFlyout { - z-index: ${theme.eui.euiZNavigation + 1}; - } - `} -`; - -interface ConfigureCasesComponentProps { - userCanCrud: boolean; -} - -const ConfigureCasesComponent: React.FC = ({ userCanCrud }) => { - const { triggersActionsUi } = useKibana().services; - - const [connectorIsValid, setConnectorIsValid] = useState(true); - const [addFlyoutVisible, setAddFlyoutVisibility] = useState(false); - const [editFlyoutVisible, setEditFlyoutVisibility] = useState(false); - const [editedConnectorItem, setEditedConnectorItem] = useState( - null - ); - - const { - connector, - closureType, - loading: loadingCaseConfigure, - mappings, - persistLoading, - persistCaseConfigure, - refetchCaseConfigure, - setConnector, - setClosureType, - } = useCaseConfigure(); - - const { loading: isLoadingConnectors, connectors, refetchConnectors } = useConnectors(); - const { loading: isLoadingActionTypes, actionTypes, refetchActionTypes } = useActionTypes(); - const supportedActionTypes = useMemo( - () => actionTypes.filter((actionType) => SUPPORTED_CONNECTORS.includes(actionType.id)), - [actionTypes] - ); - - const onConnectorUpdate = useCallback(async () => { - refetchConnectors(); - refetchActionTypes(); - refetchCaseConfigure(); - }, [refetchActionTypes, refetchCaseConfigure, refetchConnectors]); - - const isLoadingAny = - isLoadingConnectors || persistLoading || loadingCaseConfigure || isLoadingActionTypes; - const updateConnectorDisabled = isLoadingAny || !connectorIsValid || connector.id === 'none'; - const onClickUpdateConnector = useCallback(() => { - setEditFlyoutVisibility(true); - }, []); - - const onCloseAddFlyout = useCallback(() => setAddFlyoutVisibility(false), [ - setAddFlyoutVisibility, - ]); - - const onCloseEditFlyout = useCallback(() => setEditFlyoutVisibility(false), []); - - const onChangeConnector = useCallback( - (id: string) => { - if (id === 'add-connector') { - setAddFlyoutVisibility(true); - return; - } - - const actionConnector = getConnectorById(id, connectors); - const caseConnector = - actionConnector != null ? normalizeActionConnector(actionConnector) : getNoneConnector(); - - setConnector(caseConnector); - persistCaseConfigure({ - connector: caseConnector, - closureType, - }); - }, - [connectors, closureType, persistCaseConfigure, setConnector] - ); - - const onChangeClosureType = useCallback( - (type: ClosureType) => { - setClosureType(type); - persistCaseConfigure({ - connector, - closureType: type, - }); - }, - [connector, persistCaseConfigure, setClosureType] - ); - - useEffect(() => { - if ( - !isLoadingConnectors && - connector.id !== 'none' && - !connectors.some((c) => c.id === connector.id) - ) { - setConnectorIsValid(false); - } else if ( - !isLoadingConnectors && - (connector.id === 'none' || connectors.some((c) => c.id === connector.id)) - ) { - setConnectorIsValid(true); - } - }, [connectors, connector, isLoadingConnectors]); - - useEffect(() => { - if (!isLoadingConnectors && connector.id !== 'none') { - setEditedConnectorItem( - normalizeCaseConnector(connectors, connector) as ActionConnectorTableItem - ); - } - }, [connectors, connector, isLoadingConnectors]); - - const ConnectorAddFlyout = useMemo( - () => - triggersActionsUi.getAddConnectorFlyout({ - consumer: 'case', - onClose: onCloseAddFlyout, - actionTypes: supportedActionTypes, - reloadConnectors: onConnectorUpdate, - }), - // eslint-disable-next-line react-hooks/exhaustive-deps - [supportedActionTypes] - ); - - const ConnectorEditFlyout = useMemo( - () => - editedConnectorItem && editFlyoutVisible - ? triggersActionsUi.getEditConnectorFlyout({ - initialConnector: editedConnectorItem, - consumer: 'case', - onClose: onCloseEditFlyout, - reloadConnectors: onConnectorUpdate, - }) - : null, - // eslint-disable-next-line react-hooks/exhaustive-deps - [connector.id, editFlyoutVisible] - ); - - return ( - - {!connectorIsValid && ( - - - {i18n.WARNING_NO_CONNECTOR_MESSAGE} - - - )} - - - - - - - {addFlyoutVisible && ConnectorAddFlyout} - {ConnectorEditFlyout} - - ); -}; - -export const ConfigureCases = React.memo(ConfigureCasesComponent); diff --git a/x-pack/plugins/cases/public/components/configure_cases/mapping.test.tsx b/x-pack/plugins/cases/public/components/configure_cases/mapping.test.tsx deleted file mode 100644 index 75b2410dde95..000000000000 --- a/x-pack/plugins/cases/public/components/configure_cases/mapping.test.tsx +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { mount } from 'enzyme'; - -import { TestProviders } from '../../common/mock'; -import { Mapping, MappingProps } from './mapping'; -import { mappings } from './__mock__'; - -describe('Mapping', () => { - const props: MappingProps = { - connectorActionTypeId: '.servicenow', - isLoading: false, - mappings, - }; - - beforeEach(() => { - jest.clearAllMocks(); - }); - test('it shows mapping form group', () => { - const wrapper = mount(, { wrappingComponent: TestProviders }); - expect(wrapper.find('[data-test-subj="static-mappings"]').first().exists()).toBe(true); - }); - - test('correctly maps fields', () => { - const wrapper = mount(, { wrappingComponent: TestProviders }); - expect(wrapper.find('[data-test-subj="field-mapping-source"] code').first().text()).toBe( - 'title' - ); - expect(wrapper.find('[data-test-subj="field-mapping-target"] code').first().text()).toBe( - 'short_description' - ); - }); - test('displays connection warning when isLoading: false and mappings: []', () => { - const wrapper = mount(, { - wrappingComponent: TestProviders, - }); - expect(wrapper.find('[data-test-subj="field-mapping-desc"]').first().text()).toBe( - 'Field mappings require an established connection to ServiceNow ITSM. Please check your connection credentials.' - ); - }); -}); diff --git a/x-pack/plugins/cases/public/components/configure_cases/mapping.tsx b/x-pack/plugins/cases/public/components/configure_cases/mapping.tsx deleted file mode 100644 index 5ec6a33f48b6..000000000000 --- a/x-pack/plugins/cases/public/components/configure_cases/mapping.tsx +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { useMemo } from 'react'; - -import { EuiFlexGroup, EuiFlexItem, EuiText, EuiTextColor } from '@elastic/eui'; - -import { TextColor } from '@elastic/eui/src/components/text/text_color'; -import * as i18n from './translations'; - -import { FieldMapping } from './field_mapping'; -import { CaseConnectorMapping } from '../../containers/configure/types'; -import { connectorsConfiguration } from '../connectors'; - -export interface MappingProps { - connectorActionTypeId: string; - isLoading: boolean; - mappings: CaseConnectorMapping[]; -} - -const MappingComponent: React.FC = ({ - connectorActionTypeId, - isLoading, - mappings, -}) => { - const selectedConnector = useMemo(() => connectorsConfiguration[connectorActionTypeId], [ - connectorActionTypeId, - ]); - const fieldMappingDesc: { desc: string; color: TextColor } = useMemo( - () => - mappings.length > 0 || isLoading - ? { desc: i18n.FIELD_MAPPING_DESC(selectedConnector.name), color: 'subdued' } - : { desc: i18n.FIELD_MAPPING_DESC_ERR(selectedConnector.name), color: 'danger' }, - [isLoading, mappings.length, selectedConnector.name] - ); - return ( - - - -

{i18n.FIELD_MAPPING_TITLE(selectedConnector.name)}

- - {fieldMappingDesc.desc} - -
-
- - - -
- ); -}; - -export const Mapping = React.memo(MappingComponent); diff --git a/x-pack/plugins/cases/public/components/configure_cases/translations.ts b/x-pack/plugins/cases/public/components/configure_cases/translations.ts deleted file mode 100644 index 2fb2133ba470..000000000000 --- a/x-pack/plugins/cases/public/components/configure_cases/translations.ts +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; - -export * from '../../common/translations'; - -export const INCIDENT_MANAGEMENT_SYSTEM_TITLE = i18n.translate( - 'xpack.cases.configureCases.incidentManagementSystemTitle', - { - defaultMessage: 'Connect to external incident management system', - } -); - -export const INCIDENT_MANAGEMENT_SYSTEM_DESC = i18n.translate( - 'xpack.cases.configureCases.incidentManagementSystemDesc', - { - defaultMessage: - 'You may optionally connect cases to an external incident management system of your choosing. This will allow you to push case data as an incident in your chosen third-party system.', - } -); - -export const INCIDENT_MANAGEMENT_SYSTEM_LABEL = i18n.translate( - 'xpack.cases.configureCases.incidentManagementSystemLabel', - { - defaultMessage: 'Incident management system', - } -); - -export const ADD_NEW_CONNECTOR = i18n.translate('xpack.cases.configureCases.addNewConnector', { - defaultMessage: 'Add new connector', -}); - -export const CASE_CLOSURE_OPTIONS_TITLE = i18n.translate( - 'xpack.cases.configureCases.caseClosureOptionsTitle', - { - defaultMessage: 'Case Closures', - } -); - -export const CASE_CLOSURE_OPTIONS_DESC = i18n.translate( - 'xpack.cases.configureCases.caseClosureOptionsDesc', - { - defaultMessage: - 'Define how you wish cases to be closed. Automated case closures require an established connection to an external incident management system.', - } -); - -export const CASE_COLSURE_OPTIONS_SUB_CASES = i18n.translate( - 'xpack.cases.configureCases.caseClosureOptionsSubCases', - { - defaultMessage: 'Automated closures of sub-cases is not currently supported.', - } -); - -export const CASE_CLOSURE_OPTIONS_LABEL = i18n.translate( - 'xpack.cases.configureCases.caseClosureOptionsLabel', - { - defaultMessage: 'Case closure options', - } -); - -export const CASE_CLOSURE_OPTIONS_MANUAL = i18n.translate( - 'xpack.cases.configureCases.caseClosureOptionsManual', - { - defaultMessage: 'Manually close cases', - } -); - -export const CASE_CLOSURE_OPTIONS_NEW_INCIDENT = i18n.translate( - 'xpack.cases.configureCases.caseClosureOptionsNewIncident', - { - defaultMessage: 'Automatically close cases when pushing new incident to external system', - } -); - -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', { - values: { thirdPartyName }, - defaultMessage: '{ thirdPartyName } field mappings', - }); -}; - -export const FIELD_MAPPING_DESC = (thirdPartyName: string): string => { - return 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', { - values: { thirdPartyName }, - defaultMessage: - 'Field mappings require an established connection to { thirdPartyName }. Please check your connection credentials.', - }); -}; -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', - { - defaultMessage: 'Kibana case field', - } -); - -export const FIELD_MAPPING_SECOND_COL = (thirdPartyName: string): string => { - return i18n.translate('xpack.cases.configureCases.fieldMappingSecondCol', { - values: { thirdPartyName }, - defaultMessage: '{ thirdPartyName } field', - }); -}; - -export const FIELD_MAPPING_THIRD_COL = i18n.translate( - 'xpack.cases.configureCases.fieldMappingThirdCol', - { - defaultMessage: 'On edit and update', - } -); - -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', - { - defaultMessage: 'Append', - } -); - -export const CANCEL = i18n.translate('xpack.cases.configureCases.cancelButton', { - defaultMessage: 'Cancel', -}); - -export const SAVE = i18n.translate('xpack.cases.configureCases.saveButton', { - defaultMessage: 'Save', -}); - -export const SAVE_CLOSE = i18n.translate('xpack.cases.configureCases.saveAndCloseButton', { - defaultMessage: 'Save & close', -}); - -export const WARNING_NO_CONNECTOR_TITLE = i18n.translate( - 'xpack.cases.configureCases.warningTitle', - { - defaultMessage: 'Warning', - } -); - -export const WARNING_NO_CONNECTOR_MESSAGE = i18n.translate( - 'xpack.cases.configureCases.warningMessage', - { - defaultMessage: - 'The selected connector has been deleted. Either select a different connector or create a new one.', - } -); - -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', { - 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', { - values: { connectorName }, - defaultMessage: 'Update { connectorName }', - }); -}; diff --git a/x-pack/plugins/cases/public/components/configure_cases/utils.test.tsx b/x-pack/plugins/cases/public/components/configure_cases/utils.test.tsx deleted file mode 100644 index 45bb7f1f5136..000000000000 --- a/x-pack/plugins/cases/public/components/configure_cases/utils.test.tsx +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { mappings } from './__mock__'; -import { setActionTypeToMapping, setThirdPartyToMapping } from './utils'; -import { CaseConnectorMapping } from '../../containers/configure/types'; - -describe('FieldMappingRow', () => { - test('it should change the action type', () => { - const newMapping = setActionTypeToMapping('title', 'nothing', mappings); - expect(newMapping[0].actionType).toBe('nothing'); - }); - - test('it should not change other fields', () => { - const [newTitle, description, comments] = setActionTypeToMapping('title', 'nothing', mappings); - expect(newTitle).not.toEqual(mappings[0]); - expect(description).toEqual(mappings[1]); - expect(comments).toEqual(mappings[2]); - }); - - test('it should return a new array when changing action type', () => { - const newMapping = setActionTypeToMapping('title', 'nothing', mappings); - expect(newMapping).not.toBe(mappings); - }); - - test('it should change the third party', () => { - const newMapping = setThirdPartyToMapping('title', 'description', mappings); - expect(newMapping[0].target).toBe('description'); - }); - - test('it should not change other fields when there is not a conflict', () => { - const tempMapping: CaseConnectorMapping[] = [ - { - source: 'title', - target: 'short_description', - actionType: 'overwrite', - }, - { - source: 'comments', - target: 'comments', - actionType: 'append', - }, - ]; - - const [newTitle, comments] = setThirdPartyToMapping('title', 'description', tempMapping); - - expect(newTitle).not.toEqual(mappings[0]); - expect(comments).toEqual(tempMapping[1]); - }); - - test('it should return a new array when changing third party', () => { - const newMapping = setThirdPartyToMapping('title', 'description', mappings); - expect(newMapping).not.toBe(mappings); - }); - - test('it should change the target of the conflicting third party field to not_mapped', () => { - const newMapping = setThirdPartyToMapping('title', 'description', mappings); - expect(newMapping[1].target).toBe('not_mapped'); - }); -}); diff --git a/x-pack/plugins/cases/public/components/configure_cases/utils.ts b/x-pack/plugins/cases/public/components/configure_cases/utils.ts deleted file mode 100644 index ade1a5e0c2bb..000000000000 --- a/x-pack/plugins/cases/public/components/configure_cases/utils.ts +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { ConnectorTypeFields, ConnectorTypes } from '../../../common'; -import { - CaseField, - ActionType, - ThirdPartyField, - ActionConnector, - CaseConnector, - CaseConnectorMapping, -} from '../../containers/configure/types'; - -export const setActionTypeToMapping = ( - caseField: CaseField, - newActionType: ActionType, - mapping: CaseConnectorMapping[] -): CaseConnectorMapping[] => { - const findItemIndex = mapping.findIndex((item) => item.source === caseField); - - if (findItemIndex >= 0) { - return [ - ...mapping.slice(0, findItemIndex), - { ...mapping[findItemIndex], actionType: newActionType }, - ...mapping.slice(findItemIndex + 1), - ]; - } - - return [...mapping]; -}; - -export const setThirdPartyToMapping = ( - caseField: CaseField, - newThirdPartyField: ThirdPartyField, - mapping: CaseConnectorMapping[] -): CaseConnectorMapping[] => - mapping.map((item) => { - if (item.source !== caseField && item.target === newThirdPartyField) { - return { ...item, target: 'not_mapped' }; - } else if (item.source === caseField) { - return { ...item, target: newThirdPartyField }; - } - return item; - }); - -export const getNoneConnector = (): CaseConnector => ({ - id: 'none', - name: 'none', - type: ConnectorTypes.none, - fields: null, -}); - -export const getConnectorById = ( - id: string, - connectors: ActionConnector[] -): ActionConnector | null => connectors.find((c) => c.id === id) ?? null; - -export const normalizeActionConnector = ( - actionConnector: ActionConnector, - fields: CaseConnector['fields'] = null -): CaseConnector => { - const caseConnectorFieldsType = { - type: actionConnector.actionTypeId, - fields, - } as ConnectorTypeFields; - return { - id: actionConnector.id, - name: actionConnector.name, - ...caseConnectorFieldsType, - }; -}; - -export const normalizeCaseConnector = ( - connectors: ActionConnector[], - caseConnector: CaseConnector -): ActionConnector | null => connectors.find((c) => c.id === caseConnector.id) ?? null; diff --git a/x-pack/plugins/cases/public/components/connector_selector/form.test.tsx b/x-pack/plugins/cases/public/components/connector_selector/form.test.tsx deleted file mode 100644 index ec136989dd93..000000000000 --- a/x-pack/plugins/cases/public/components/connector_selector/form.test.tsx +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { mount } from 'enzyme'; -import { UseField, Form, useForm, FormHook } from '../../common/shared_imports'; -import { ConnectorSelector } from './form'; -import { connectorsMock } from '../../containers/mock'; -import { getFormMock } from '../__mock__/form'; - -jest.mock('../../../../../../src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_form'); - -const useFormMock = useForm as jest.Mock; - -describe('ConnectorSelector', () => { - const formHookMock = getFormMock({ connectorId: connectorsMock[0].id }); - - beforeEach(() => { - jest.resetAllMocks(); - useFormMock.mockImplementation(() => ({ form: formHookMock })); - }); - - it('it should render', async () => { - const wrapper = mount( -
- - - ); - - expect(wrapper.find(`[data-test-subj="caseConnectors"]`).exists()).toBeTruthy(); - }); - - it('it should not render when is not in edit mode', async () => { - const wrapper = mount( -
- - - ); - - expect(wrapper.find(`[data-test-subj="caseConnectors"]`).exists()).toBeFalsy(); - }); -}); diff --git a/x-pack/plugins/cases/public/components/connector_selector/form.tsx b/x-pack/plugins/cases/public/components/connector_selector/form.tsx deleted file mode 100644 index 210334e93adb..000000000000 --- a/x-pack/plugins/cases/public/components/connector_selector/form.tsx +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { useCallback } from 'react'; -import { isEmpty } from 'lodash/fp'; -import { EuiFormRow } from '@elastic/eui'; - -import { FieldHook, getFieldValidityAndErrorMessage } from '../../common/shared_imports'; -import { ConnectorsDropdown } from '../configure_cases/connectors_dropdown'; -import { ActionConnector } from '../../../common'; - -interface ConnectorSelectorProps { - connectors: ActionConnector[]; - dataTestSubj: string; - disabled: boolean; - field: FieldHook; - idAria: string; - isEdit: boolean; - isLoading: boolean; - handleChange?: (newValue: string) => void; - hideConnectorServiceNowSir?: boolean; -} -export const ConnectorSelector = ({ - connectors, - dataTestSubj, - disabled = false, - field, - idAria, - isEdit = true, - isLoading = false, - handleChange, - hideConnectorServiceNowSir = false, -}: ConnectorSelectorProps) => { - const { isInvalid, errorMessage } = getFieldValidityAndErrorMessage(field); - const onChange = useCallback( - (val: string) => { - if (handleChange) { - handleChange(val); - } - field.setValue(val); - }, - [handleChange, field] - ); - - return isEdit ? ( - - - - ) : null; -}; diff --git a/x-pack/plugins/cases/public/components/connectors/card.tsx b/x-pack/plugins/cases/public/components/connectors/card.tsx deleted file mode 100644 index 82a508ccf343..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/card.tsx +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { memo, useMemo } from 'react'; -import { EuiCard, EuiIcon, EuiLoadingSpinner } from '@elastic/eui'; -import styled from 'styled-components'; - -import { connectorsConfiguration } from '.'; -import { ConnectorTypes } from '../../../common'; - -interface ConnectorCardProps { - connectorType: ConnectorTypes; - title: string; - listItems: Array<{ title: string; description: React.ReactNode }>; - isLoading: boolean; -} - -const StyledText = styled.span` - span { - display: block; - } -`; - -const ConnectorCardDisplay: React.FC = ({ - connectorType, - title, - listItems, - isLoading, -}) => { - const description = useMemo( - () => ( - - {listItems.length > 0 && - listItems.map((item, i) => ( - - {`${item.title}: `} - {item.description} - - ))} - - ), - [listItems] - ); - const icon = useMemo( - () => , - [connectorType] - ); - return ( - <> - {isLoading && } - {!isLoading && ( - - )} - - ); -}; - -export const ConnectorCard = memo(ConnectorCardDisplay); diff --git a/x-pack/plugins/cases/public/components/connectors/case/alert_fields.tsx b/x-pack/plugins/cases/public/components/connectors/case/alert_fields.tsx deleted file mode 100644 index 10955db69461..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/case/alert_fields.tsx +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -/* eslint-disable @kbn/eslint/no-restricted-paths */ - -import React, { useCallback, useEffect, useState } from 'react'; -import styled from 'styled-components'; -import { EuiCallOut, EuiSpacer } from '@elastic/eui'; - -import { ActionParamsProps } from '../../../../../triggers_actions_ui/public/types'; -import { CommentType } from '../../../../common'; - -import { CaseActionParams } from './types'; -import { ExistingCase } from './existing_case'; - -import * as i18n from './translations'; - -const Container = styled.div` - ${({ theme }) => ` - padding: ${theme.eui?.euiSizeS ?? '8px'} ${theme.eui?.euiSizeL ?? '24px'} ${ - theme.eui?.euiSizeL ?? '24px' - } ${theme.eui?.euiSizeL ?? '24px'}; - `} -`; - -const defaultAlertComment = { - type: CommentType.generatedAlert, - alerts: `[{{#context.alerts}}{"_id": "{{_id}}", "_index": "{{_index}}", "ruleId": "{{signal.rule.id}}", "ruleName": "{{signal.rule.name}}"}__SEPARATOR__{{/context.alerts}}]`, -}; - -const CaseParamsFields: React.FunctionComponent> = ({ - actionParams, - editAction, - index, - errors, - messageVariables, - actionConnector, -}) => { - const { caseId = null, comment = defaultAlertComment } = actionParams.subActionParams ?? {}; - - const [selectedCase, setSelectedCase] = useState(null); - - const editSubActionProperty = useCallback( - (key: string, value: unknown) => { - const newProps = { ...actionParams.subActionParams, [key]: value }; - editAction('subActionParams', newProps, index); - }, - // edit action causes re-renders - // eslint-disable-next-line react-hooks/exhaustive-deps - [actionParams.subActionParams, index] - ); - - const onCaseChanged = useCallback( - (id: string) => { - setSelectedCase(id); - editSubActionProperty('caseId', id); - }, - [editSubActionProperty] - ); - - useEffect(() => { - if (!actionParams.subAction) { - editAction('subAction', 'addComment', index); - } - - if (!actionParams.subActionParams?.caseId) { - editSubActionProperty('caseId', caseId); - } - - if (!actionParams.subActionParams?.comment) { - editSubActionProperty('comment', comment); - } - - if (caseId != null) { - setSelectedCase((prevCaseId) => (prevCaseId !== caseId ? caseId : prevCaseId)); - } - - // editAction creates an infinity loop. - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [ - actionConnector, - index, - actionParams.subActionParams?.caseId, - actionParams.subActionParams?.comment, - caseId, - comment, - actionParams.subAction, - ]); - - return ( - - - - -

{i18n.CASE_CONNECTOR_CALL_OUT_MSG}

-
-
- ); -}; - -// eslint-disable-next-line import/no-default-export -export { CaseParamsFields as default }; diff --git a/x-pack/plugins/cases/public/components/connectors/case/cases_dropdown.tsx b/x-pack/plugins/cases/public/components/connectors/case/cases_dropdown.tsx deleted file mode 100644 index 3f3c7d493119..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/case/cases_dropdown.tsx +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiFormRow, EuiSuperSelect, EuiSuperSelectOption } from '@elastic/eui'; -import React, { memo, useMemo, useCallback } from 'react'; -import { Case } from '../../../containers/types'; - -import * as i18n from './translations'; - -interface CaseDropdownProps { - isLoading: boolean; - cases: Case[]; - selectedCase?: string; - onCaseChanged: (id: string) => void; -} - -export const ADD_CASE_BUTTON_ID = 'add-case'; - -const addNewCase = { - value: ADD_CASE_BUTTON_ID, - inputDisplay: ( - - {i18n.CASE_CONNECTOR_ADD_NEW_CASE} - - ), - 'data-test-subj': 'dropdown-connector-add-connector', -}; - -const CasesDropdownComponent: React.FC = ({ - isLoading, - cases, - selectedCase, - onCaseChanged, -}) => { - const caseOptions: Array> = useMemo( - () => - cases.reduce>>( - (acc, theCase) => [ - ...acc, - { - value: theCase.id, - inputDisplay: {theCase.title}, - 'data-test-subj': `case-connector-cases-dropdown-${theCase.id}`, - }, - ], - [] - ), - [cases] - ); - - const options = useMemo(() => [...caseOptions, addNewCase], [caseOptions]); - const onChange = useCallback((id: string) => onCaseChanged(id), [onCaseChanged]); - - return ( - - - - ); -}; - -export const CasesDropdown = memo(CasesDropdownComponent); diff --git a/x-pack/plugins/cases/public/components/connectors/case/existing_case.tsx b/x-pack/plugins/cases/public/components/connectors/case/existing_case.tsx deleted file mode 100644 index 22798843dd85..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/case/existing_case.tsx +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { memo, useMemo, useCallback } from 'react'; -import { CaseType } from '../../../../common'; -import { - useGetCases, - DEFAULT_QUERY_PARAMS, - DEFAULT_FILTER_OPTIONS, -} from '../../../containers/use_get_cases'; -import { useCreateCaseModal } from '../../use_create_case_modal'; -import { CasesDropdown, ADD_CASE_BUTTON_ID } from './cases_dropdown'; - -interface ExistingCaseProps { - selectedCase: string | null; - onCaseChanged: (id: string) => void; -} - -const ExistingCaseComponent: React.FC = ({ onCaseChanged, selectedCase }) => { - const { data: cases, loading: isLoadingCases, refetchCases } = useGetCases(DEFAULT_QUERY_PARAMS, { - ...DEFAULT_FILTER_OPTIONS, - onlyCollectionType: true, - }); - - const onCaseCreated = useCallback( - (newCase) => { - refetchCases(); - onCaseChanged(newCase.id); - }, - [onCaseChanged, refetchCases] - ); - - const { modal, openModal } = useCreateCaseModal({ - onCaseCreated, - caseType: CaseType.collection, - // FUTURE DEVELOPER - // We are making the assumption that this component is only used in rules creation - // that's why we want to hide ServiceNow SIR - hideConnectorServiceNowSir: true, - }); - - const onChange = useCallback( - (id: string) => { - if (id === ADD_CASE_BUTTON_ID) { - openModal(); - return; - } - - onCaseChanged(id); - }, - [onCaseChanged, openModal] - ); - - const isCasesLoading = useMemo( - () => isLoadingCases.includes('cases') || isLoadingCases.includes('caseUpdate'), - [isLoadingCases] - ); - - return ( - <> - - {modal} - - ); -}; - -export const ExistingCase = memo(ExistingCaseComponent); diff --git a/x-pack/plugins/cases/public/components/connectors/case/index.ts b/x-pack/plugins/cases/public/components/connectors/case/index.ts deleted file mode 100644 index c2cf4980da7e..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/case/index.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { lazy } from 'react'; - -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { ActionTypeModel } from '../../../../../triggers_actions_ui/public/types'; -import { CaseActionParams } from './types'; -import * as i18n from './translations'; - -interface ValidationResult { - errors: { - caseId: string[]; - }; -} - -const validateParams = (actionParams: CaseActionParams) => { - const validationResult: ValidationResult = { errors: { caseId: [] } }; - - if (actionParams.subActionParams && !actionParams.subActionParams.caseId) { - validationResult.errors.caseId.push(i18n.CASE_CONNECTOR_CASE_REQUIRED); - } - - return validationResult; -}; - -export function getActionType(): ActionTypeModel { - return { - id: '.case', - iconClass: 'securityAnalyticsApp', - selectMessage: i18n.CASE_CONNECTOR_DESC, - actionTypeTitle: i18n.CASE_CONNECTOR_TITLE, - validateConnector: () => ({ config: { errors: {} }, secrets: { errors: {} } }), - validateParams, - actionConnectorFields: null, - actionParamsFields: lazy(() => import('./alert_fields')), - }; -} diff --git a/x-pack/plugins/cases/public/components/connectors/case/translations.ts b/x-pack/plugins/cases/public/components/connectors/case/translations.ts deleted file mode 100644 index 8304aaef5765..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/case/translations.ts +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; - -export * from '../../../common/translations'; - -export const CASE_CONNECTOR_DESC = i18n.translate( - 'xpack.cases.components.connectors.cases.selectMessageText', - { - defaultMessage: 'Create or update a case.', - } -); - -export const CASE_CONNECTOR_TITLE = i18n.translate( - 'xpack.cases.components.connectors.cases.actionTypeTitle', - { - 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', - { - defaultMessage: 'Case allowing sub-cases', - } -); - -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', - { - defaultMessage: 'Add to existing case', - } -); - -export const CASE_CONNECTOR_CASE_REQUIRED = i18n.translate( - 'xpack.cases.components.connectors.cases.caseRequired', - { - defaultMessage: 'You must select a case.', - } -); - -export const CASE_CONNECTOR_CALL_OUT_TITLE = i18n.translate( - 'xpack.cases.components.connectors.cases.callOutTitle', - { - defaultMessage: 'Generated alerts will be attached to sub-cases', - } -); - -export const CASE_CONNECTOR_CALL_OUT_MSG = i18n.translate( - 'xpack.cases.components.connectors.cases.callOutMsg', - { - defaultMessage: - 'A case can contain multiple sub-cases to allow grouping of generated alerts. Sub-cases will give more granular control over the status of these generated alerts and prevents having too many alerts attached to one case.', - } -); - -export const CASE_CONNECTOR_ADD_NEW_CASE = i18n.translate( - 'xpack.cases.components.connectors.cases.addNewCaseOption', - { - defaultMessage: 'Add new case', - } -); - -export const CREATE_CASE = i18n.translate( - 'xpack.cases.components.connectors.cases.createCaseLabel', - { - defaultMessage: 'Create case', - } -); - -export const CONNECTED_CASE = i18n.translate( - 'xpack.cases.components.connectors.cases.connectedCaseLabel', - { - defaultMessage: 'Connected case', - } -); diff --git a/x-pack/plugins/cases/public/components/connectors/case/types.ts b/x-pack/plugins/cases/public/components/connectors/case/types.ts deleted file mode 100644 index aec9e09ea198..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/case/types.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export interface CaseActionParams { - subAction: string; - subActionParams: { - caseId: string; - comment: { - alertId: string; - index: string; - type: 'alert'; - }; - }; -} diff --git a/x-pack/plugins/cases/public/components/connectors/config.ts b/x-pack/plugins/cases/public/components/connectors/config.ts deleted file mode 100644 index e8d87511c7e1..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/config.ts +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - getResilientActionType, - getServiceNowITSMActionType, - getServiceNowSIRActionType, - getJiraActionType, - // eslint-disable-next-line @kbn/eslint/no-restricted-paths -} from '../../../../triggers_actions_ui/public/common'; -import { ConnectorConfiguration } from './types'; - -const resilient = getResilientActionType(); -const serviceNowITSM = getServiceNowITSMActionType(); -const serviceNowSIR = getServiceNowSIRActionType(); -const jira = getJiraActionType(); - -export const connectorsConfiguration: Record = { - '.servicenow': { - name: serviceNowITSM.actionTypeTitle ?? '', - logo: serviceNowITSM.iconClass, - }, - '.servicenow-sir': { - name: serviceNowSIR.actionTypeTitle ?? '', - logo: serviceNowSIR.iconClass, - }, - '.jira': { - name: jira.actionTypeTitle ?? '', - logo: jira.iconClass, - }, - '.resilient': { - name: resilient.actionTypeTitle ?? '', - logo: resilient.iconClass, - }, -}; diff --git a/x-pack/plugins/cases/public/components/connectors/connectors_registry.ts b/x-pack/plugins/cases/public/components/connectors/connectors_registry.ts deleted file mode 100644 index 2e02cb290c3c..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/connectors_registry.ts +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; -import { CaseConnector, CaseConnectorsRegistry } from './types'; - -export const createCaseConnectorsRegistry = (): CaseConnectorsRegistry => { - const connectors: Map> = new Map(); - - const registry: CaseConnectorsRegistry = { - has: (id: string) => connectors.has(id), - register: (connector: CaseConnector) => { - if (connectors.has(connector.id)) { - throw new Error( - i18n.translate('xpack.cases.connecors.register.duplicateCaseConnectorErrorMessage', { - defaultMessage: 'Object type "{id}" is already registered.', - values: { - id: connector.id, - }, - }) - ); - } - - connectors.set(connector.id, connector); - }, - get: (id: string): CaseConnector => { - if (!connectors.has(id)) { - throw new Error( - i18n.translate('xpack.cases.connecors.get.missingCaseConnectorErrorMessage', { - defaultMessage: 'Object type "{id}" is not registered.', - values: { - id, - }, - }) - ); - } - return connectors.get(id)!; - }, - list: () => { - return Array.from(connectors).map(([id, connector]) => connector); - }, - }; - - return registry; -}; diff --git a/x-pack/plugins/cases/public/components/connectors/fields_form.tsx b/x-pack/plugins/cases/public/components/connectors/fields_form.tsx deleted file mode 100644 index d71da6f87689..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/fields_form.tsx +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { memo, Suspense } from 'react'; -import { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner } from '@elastic/eui'; - -import { CaseActionConnector, ConnectorFieldsProps } from './types'; -import { getCaseConnectors } from '.'; -import { ConnectorTypeFields } from '../../../common'; - -interface Props extends Omit, 'connector'> { - connector: CaseActionConnector | null; -} - -const ConnectorFieldsFormComponent: React.FC = ({ connector, isEdit, onChange, fields }) => { - const { caseConnectorsRegistry } = getCaseConnectors(); - - if (connector == null || connector.actionTypeId == null || connector.actionTypeId === '.none') { - return null; - } - - const { fieldsComponent: FieldsComponent } = caseConnectorsRegistry.get(connector.actionTypeId); - - return ( - <> - {FieldsComponent != null ? ( - - - - - - } - > -
- -
-
- ) : null} - - ); -}; - -export const ConnectorFieldsForm = memo(ConnectorFieldsFormComponent); diff --git a/x-pack/plugins/cases/public/components/connectors/index.ts b/x-pack/plugins/cases/public/components/connectors/index.ts deleted file mode 100644 index 7444c403a3b6..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/index.ts +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { CaseConnectorsRegistry } from './types'; -import { createCaseConnectorsRegistry } from './connectors_registry'; -import { getCaseConnector as getJiraCaseConnector } from './jira'; -import { getCaseConnector as getResilientCaseConnector } from './resilient'; -import { getServiceNowITSMCaseConnector, getServiceNowSIRCaseConnector } from './servicenow'; -import { - JiraFieldsType, - ServiceNowITSMFieldsType, - ServiceNowSIRFieldsType, - ResilientFieldsType, -} from '../../../common'; - -export { getActionType as getCaseConnectorUI } from './case'; - -export * from './config'; -export * from './types'; - -interface GetCaseConnectorsReturn { - caseConnectorsRegistry: CaseConnectorsRegistry; -} - -class CaseConnectors { - private caseConnectorsRegistry: CaseConnectorsRegistry; - - constructor() { - this.caseConnectorsRegistry = createCaseConnectorsRegistry(); - this.init(); - } - - private init() { - this.caseConnectorsRegistry.register(getJiraCaseConnector()); - this.caseConnectorsRegistry.register(getResilientCaseConnector()); - this.caseConnectorsRegistry.register( - getServiceNowITSMCaseConnector() - ); - this.caseConnectorsRegistry.register(getServiceNowSIRCaseConnector()); - } - - registry(): CaseConnectorsRegistry { - return this.caseConnectorsRegistry; - } -} - -const caseConnectors = new CaseConnectors(); - -export const getCaseConnectors = (): GetCaseConnectorsReturn => { - return { - caseConnectorsRegistry: caseConnectors.registry(), - }; -}; diff --git a/x-pack/plugins/cases/public/components/connectors/jira/__mocks__/api.ts b/x-pack/plugins/cases/public/components/connectors/jira/__mocks__/api.ts deleted file mode 100644 index 3a7b51545dfc..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/jira/__mocks__/api.ts +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { GetIssueTypesProps, GetFieldsByIssueTypeProps, GetIssueTypeProps } from '../api'; -import { IssueTypes, Fields, Issues, Issue } from '../types'; -import { issues } from '../../mock'; - -const issueTypes = [ - { - id: '10006', - name: 'Task', - }, - { - id: '10007', - name: 'Bug', - }, -]; - -const fieldsByIssueType = { - summary: { allowedValues: [], defaultValue: {} }, - priority: { - allowedValues: [ - { - name: 'Medium', - id: '3', - }, - ], - defaultValue: { name: 'Medium', id: '3' }, - }, -}; - -export const getIssue = async (props: GetIssueTypeProps): Promise<{ data: Issue }> => - Promise.resolve({ data: issues[0] }); -export const getIssues = async (props: GetIssueTypesProps): Promise<{ data: Issues }> => - Promise.resolve({ data: issues }); -export const getIssueTypes = async (props: GetIssueTypesProps): Promise<{ data: IssueTypes }> => - Promise.resolve({ data: issueTypes }); - -export const getFieldsByIssueType = async ( - props: GetFieldsByIssueTypeProps -): Promise<{ data: Fields }> => Promise.resolve({ data: fieldsByIssueType }); diff --git a/x-pack/plugins/cases/public/components/connectors/jira/api.test.ts b/x-pack/plugins/cases/public/components/connectors/jira/api.test.ts deleted file mode 100644 index bbab8a14b5ed..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/jira/api.test.ts +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { httpServiceMock } from '../../../../../../../src/core/public/mocks'; -import { getIssueTypes, getFieldsByIssueType, getIssues, getIssue } from './api'; - -const issueTypesResponse = { - data: { - projects: [ - { - issuetypes: [ - { - id: '10006', - name: 'Task', - }, - { - id: '10007', - name: 'Bug', - }, - ], - }, - ], - }, -}; - -const fieldsResponse = { - data: { - projects: [ - { - issuetypes: [ - { - id: '10006', - name: 'Task', - fields: { - summary: { fieldId: 'summary' }, - priority: { - fieldId: 'priority', - allowedValues: [ - { - name: 'Highest', - id: '1', - }, - { - name: 'High', - id: '2', - }, - { - name: 'Medium', - id: '3', - }, - { - name: 'Low', - id: '4', - }, - { - name: 'Lowest', - id: '5', - }, - ], - defaultValue: { - name: 'Medium', - id: '3', - }, - }, - }, - }, - ], - }, - ], - }, -}; - -const issueResponse = { - id: '10267', - key: 'RJ-107', - fields: { summary: 'Test title' }, -}; - -const issuesResponse = [issueResponse]; - -describe('Jira API', () => { - const http = httpServiceMock.createStartContract(); - - beforeEach(() => jest.resetAllMocks()); - - describe('getIssueTypes', () => { - test('should call get issue types API', async () => { - const abortCtrl = new AbortController(); - http.post.mockResolvedValueOnce(issueTypesResponse); - const res = await getIssueTypes({ http, signal: abortCtrl.signal, connectorId: 'test' }); - - expect(res).toEqual(issueTypesResponse); - expect(http.post).toHaveBeenCalledWith('/api/actions/action/test/_execute', { - body: '{"params":{"subAction":"issueTypes","subActionParams":{}}}', - signal: abortCtrl.signal, - }); - }); - }); - - describe('getFieldsByIssueType', () => { - test('should call get fields API', async () => { - const abortCtrl = new AbortController(); - http.post.mockResolvedValueOnce(fieldsResponse); - const res = await getFieldsByIssueType({ - http, - signal: abortCtrl.signal, - connectorId: 'test', - id: '10006', - }); - - expect(res).toEqual(fieldsResponse); - expect(http.post).toHaveBeenCalledWith('/api/actions/action/test/_execute', { - body: '{"params":{"subAction":"fieldsByIssueType","subActionParams":{"id":"10006"}}}', - signal: abortCtrl.signal, - }); - }); - }); - - describe('getIssues', () => { - test('should call get fields API', async () => { - const abortCtrl = new AbortController(); - http.post.mockResolvedValueOnce(issuesResponse); - const res = await getIssues({ - http, - signal: abortCtrl.signal, - connectorId: 'test', - title: 'test issue', - }); - - expect(res).toEqual(issuesResponse); - expect(http.post).toHaveBeenCalledWith('/api/actions/action/test/_execute', { - body: '{"params":{"subAction":"issues","subActionParams":{"title":"test issue"}}}', - signal: abortCtrl.signal, - }); - }); - }); - - describe('getIssue', () => { - test('should call get fields API', async () => { - const abortCtrl = new AbortController(); - http.post.mockResolvedValueOnce(issuesResponse); - const res = await getIssue({ - http, - signal: abortCtrl.signal, - connectorId: 'test', - id: 'RJ-107', - }); - - expect(res).toEqual(issuesResponse); - expect(http.post).toHaveBeenCalledWith('/api/actions/action/test/_execute', { - body: '{"params":{"subAction":"issue","subActionParams":{"id":"RJ-107"}}}', - signal: abortCtrl.signal, - }); - }); - }); -}); diff --git a/x-pack/plugins/cases/public/components/connectors/jira/api.ts b/x-pack/plugins/cases/public/components/connectors/jira/api.ts deleted file mode 100644 index dff3e3a5b41a..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/jira/api.ts +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { HttpSetup } from 'kibana/public'; -import { ActionTypeExecutorResult } from '../../../../../actions/common'; -import { IssueTypes, Fields, Issues, Issue } from './types'; - -export const BASE_ACTION_API_PATH = '/api/actions'; - -export interface GetIssueTypesProps { - http: HttpSetup; - signal: AbortSignal; - connectorId: string; -} - -export async function getIssueTypes({ http, signal, connectorId }: GetIssueTypesProps) { - return http.post>( - `${BASE_ACTION_API_PATH}/action/${connectorId}/_execute`, - { - body: JSON.stringify({ - params: { subAction: 'issueTypes', subActionParams: {} }, - }), - signal, - } - ); -} - -export interface GetFieldsByIssueTypeProps { - http: HttpSetup; - signal: AbortSignal; - connectorId: string; - id: string; -} - -export async function getFieldsByIssueType({ - http, - signal, - connectorId, - id, -}: GetFieldsByIssueTypeProps): Promise> { - return http.post(`${BASE_ACTION_API_PATH}/action/${connectorId}/_execute`, { - body: JSON.stringify({ - params: { subAction: 'fieldsByIssueType', subActionParams: { id } }, - }), - signal, - }); -} - -export interface GetIssuesTypeProps { - http: HttpSetup; - signal: AbortSignal; - connectorId: string; - title: string; -} - -export async function getIssues({ - http, - signal, - connectorId, - title, -}: GetIssuesTypeProps): Promise> { - return http.post(`${BASE_ACTION_API_PATH}/action/${connectorId}/_execute`, { - body: JSON.stringify({ - params: { subAction: 'issues', subActionParams: { title } }, - }), - signal, - }); -} - -export interface GetIssueTypeProps { - http: HttpSetup; - signal: AbortSignal; - connectorId: string; - id: string; -} - -export async function getIssue({ - http, - signal, - connectorId, - id, -}: GetIssueTypeProps): Promise> { - return http.post(`${BASE_ACTION_API_PATH}/action/${connectorId}/_execute`, { - body: JSON.stringify({ - params: { subAction: 'issue', subActionParams: { id } }, - }), - signal, - }); -} diff --git a/x-pack/plugins/cases/public/components/connectors/jira/case_fields.test.tsx b/x-pack/plugins/cases/public/components/connectors/jira/case_fields.test.tsx deleted file mode 100644 index 38a1e3061620..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/jira/case_fields.test.tsx +++ /dev/null @@ -1,262 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { mount } from 'enzyme'; -import { omit } from 'lodash/fp'; - -import { connector, issues } from '../mock'; -import { useGetIssueTypes } from './use_get_issue_types'; -import { useGetFieldsByIssueType } from './use_get_fields_by_issue_type'; -import Fields from './case_fields'; -import { waitFor } from '@testing-library/dom'; -import { useGetSingleIssue } from './use_get_single_issue'; -import { useGetIssues } from './use_get_issues'; -import { EuiComboBox, EuiComboBoxOptionOption } from '@elastic/eui'; - -jest.mock('./use_get_issue_types'); -jest.mock('./use_get_fields_by_issue_type'); -jest.mock('./use_get_single_issue'); -jest.mock('./use_get_issues'); -jest.mock('../../../common/lib/kibana'); -const useGetIssueTypesMock = useGetIssueTypes as jest.Mock; -const useGetFieldsByIssueTypeMock = useGetFieldsByIssueType as jest.Mock; -const useGetSingleIssueMock = useGetSingleIssue as jest.Mock; -const useGetIssuesMock = useGetIssues as jest.Mock; - -describe('Jira Fields', () => { - const useGetIssueTypesResponse = { - isLoading: false, - issueTypes: [ - { - id: '10006', - name: 'Task', - }, - { - id: '10007', - name: 'Bug', - }, - ], - }; - - const useGetFieldsByIssueTypeResponse = { - isLoading: false, - fields: { - summary: { allowedValues: [], defaultValue: {} }, - labels: { allowedValues: [], defaultValue: {} }, - description: { allowedValues: [], defaultValue: {} }, - priority: { - allowedValues: [ - { - name: 'Medium', - id: '3', - }, - { - name: 'Low', - id: '2', - }, - ], - defaultValue: { name: 'Medium', id: '3' }, - }, - }, - }; - - const useGetSingleIssueResponse = { - isLoading: false, - issue: { title: 'Parent Task', key: 'parentId' }, - }; - - const fields = { - issueType: '10006', - priority: 'High', - parent: null, - }; - - const useGetIssuesResponse = { - isLoading: false, - issues, - }; - - const onChange = jest.fn(); - - beforeEach(() => { - useGetIssueTypesMock.mockReturnValue(useGetIssueTypesResponse); - useGetFieldsByIssueTypeMock.mockReturnValue(useGetFieldsByIssueTypeResponse); - useGetSingleIssueMock.mockReturnValue(useGetSingleIssueResponse); - jest.clearAllMocks(); - }); - - test('all params fields are rendered - isEdit: true', () => { - const wrapper = mount(); - expect(wrapper.find('[data-test-subj="issueTypeSelect"]').first().prop('value')).toStrictEqual( - '10006' - ); - expect(wrapper.find('[data-test-subj="prioritySelect"]').first().prop('value')).toStrictEqual( - 'High' - ); - expect(wrapper.find('[data-test-subj="search-parent-issues"]').first().exists()).toBeFalsy(); - }); - - test('all params fields are rendered - isEdit: false', () => { - const wrapper = mount( - - ); - expect(wrapper.find('[data-test-subj="card-list-item"]').at(0).text()).toEqual( - 'Issue type: Task' - ); - expect(wrapper.find('[data-test-subj="card-list-item"]').at(1).text()).toEqual( - 'Parent issue: Parent Task' - ); - expect(wrapper.find('[data-test-subj="card-list-item"]').at(2).text()).toEqual( - 'Priority: High' - ); - }); - - test('it sets parent correctly', async () => { - useGetFieldsByIssueTypeMock.mockReturnValue({ - ...useGetFieldsByIssueTypeResponse, - fields: { - ...useGetFieldsByIssueTypeResponse.fields, - parent: {}, - }, - }); - useGetIssuesMock.mockReturnValue(useGetIssuesResponse); - const wrapper = mount(); - - await waitFor(() => - ((wrapper.find(EuiComboBox).props() as unknown) as { - onChange: (a: EuiComboBoxOptionOption[]) => void; - }).onChange([{ label: 'parentId', value: 'parentId' }]) - ); - wrapper.update(); - expect(onChange).toHaveBeenCalledWith({ - issueType: '10006', - parent: 'parentId', - priority: 'High', - }); - }); - test('it searches parent correctly', async () => { - useGetFieldsByIssueTypeMock.mockReturnValue({ - ...useGetFieldsByIssueTypeResponse, - fields: { - ...useGetFieldsByIssueTypeResponse.fields, - parent: {}, - }, - }); - useGetSingleIssueMock.mockReturnValue({ useGetSingleIssueResponse, issue: null }); - useGetIssuesMock.mockReturnValue(useGetIssuesResponse); - const wrapper = mount(); - - await waitFor(() => - ((wrapper.find(EuiComboBox).props() as unknown) as { - onSearchChange: (a: string) => void; - }).onSearchChange('womanId') - ); - wrapper.update(); - expect(useGetIssuesMock.mock.calls[2][0].query).toEqual('womanId'); - }); - - test('it disabled the fields when loading issue types', () => { - useGetIssueTypesMock.mockReturnValue({ ...useGetIssueTypesResponse, isLoading: true }); - - const wrapper = mount(); - - expect( - wrapper.find('[data-test-subj="issueTypeSelect"]').first().prop('disabled') - ).toBeTruthy(); - expect(wrapper.find('[data-test-subj="prioritySelect"]').first().prop('disabled')).toBeTruthy(); - }); - - test('it disabled the fields when loading fields', () => { - useGetFieldsByIssueTypeMock.mockReturnValue({ - ...useGetFieldsByIssueTypeResponse, - isLoading: true, - }); - - const wrapper = mount(); - - expect( - wrapper.find('[data-test-subj="issueTypeSelect"]').first().prop('disabled') - ).toBeTruthy(); - expect(wrapper.find('[data-test-subj="prioritySelect"]').first().prop('disabled')).toBeTruthy(); - }); - - test('it hides the priority if not supported', () => { - const response = omit('fields.priority', useGetFieldsByIssueTypeResponse); - - useGetFieldsByIssueTypeMock.mockReturnValue(response); - - const wrapper = mount(); - - expect(wrapper.find('[data-test-subj="prioritySelect"]').first().exists()).toBeFalsy(); - }); - - test('it sets issue type correctly', () => { - const wrapper = mount(); - - wrapper - .find('select[data-test-subj="issueTypeSelect"]') - .first() - .simulate('change', { - target: { value: '10007' }, - }); - - expect(onChange).toHaveBeenCalledWith({ issueType: '10007', parent: null, priority: null }); - }); - - test('it sets issue type when it comes as null', () => { - const wrapper = mount( - - ); - expect(wrapper.find('select[data-test-subj="issueTypeSelect"]').first().props().value).toEqual( - '10006' - ); - }); - - test('it sets issue type when it comes as unknown value', () => { - const wrapper = mount( - - ); - expect(wrapper.find('select[data-test-subj="issueTypeSelect"]').first().props().value).toEqual( - '10006' - ); - }); - - test('it sets priority correctly', () => { - const wrapper = mount(); - - wrapper - .find('select[data-test-subj="prioritySelect"]') - .first() - .simulate('change', { - target: { value: '2' }, - }); - - expect(onChange).toHaveBeenCalledWith({ issueType: '10006', parent: null, priority: '2' }); - }); - - test('it resets priority when changing issue type', () => { - const wrapper = mount(); - wrapper - .find('select[data-test-subj="issueTypeSelect"]') - .first() - .simulate('change', { - target: { value: '10007' }, - }); - - expect(onChange).toBeCalledWith({ issueType: '10007', parent: null, priority: null }); - }); -}); diff --git a/x-pack/plugins/cases/public/components/connectors/jira/case_fields.tsx b/x-pack/plugins/cases/public/components/connectors/jira/case_fields.tsx deleted file mode 100644 index 6aff81f38001..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/jira/case_fields.tsx +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { useCallback, useMemo, useEffect, useRef } from 'react'; -import { map } from 'lodash/fp'; -import { EuiFormRow, EuiSelect, EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; -import * as i18n from './translations'; - -import { ConnectorTypes, JiraFieldsType } from '../../../../common'; -import { useKibana } from '../../../common/lib/kibana'; -import { ConnectorFieldsProps } from '../types'; -import { useGetIssueTypes } from './use_get_issue_types'; -import { useGetFieldsByIssueType } from './use_get_fields_by_issue_type'; -import { SearchIssues } from './search_issues'; -import { ConnectorCard } from '../card'; - -const JiraFieldsComponent: React.FunctionComponent> = ({ - connector, - fields, - isEdit = true, - onChange, -}) => { - const init = useRef(true); - const { issueType = null, priority = null, parent = null } = fields ?? {}; - const { http, notifications } = useKibana().services; - - const handleIssueType = useCallback( - (issueTypeSelectOptions: Array<{ value: string; text: string }>) => { - if (issueType == null && issueTypeSelectOptions.length > 0) { - // if there is no issue type set in the edit view, set it to default - if (isEdit) { - onChange({ - issueType: issueTypeSelectOptions[0].value, - parent, - priority, - }); - } - } - }, - [isEdit, issueType, onChange, parent, priority] - ); - const { isLoading: isLoadingIssueTypes, issueTypes } = useGetIssueTypes({ - connector, - http, - toastNotifications: notifications.toasts, - handleIssueType, - }); - - const issueTypesSelectOptions = useMemo( - () => - issueTypes.map((type) => ({ - text: type.name ?? '', - value: type.id ?? '', - })), - [issueTypes] - ); - - const currentIssueType = useMemo(() => { - if (!issueType && issueTypesSelectOptions.length > 0) { - return issueTypesSelectOptions[0].value; - } else if ( - issueTypesSelectOptions.length > 0 && - !issueTypesSelectOptions.some(({ value }) => value === issueType) - ) { - return issueTypesSelectOptions[0].value; - } - return issueType; - }, [issueType, issueTypesSelectOptions]); - - const { isLoading: isLoadingFields, fields: fieldsByIssueType } = useGetFieldsByIssueType({ - connector, - http, - issueType: currentIssueType, - toastNotifications: notifications.toasts, - }); - - const hasPriority = useMemo(() => fieldsByIssueType.priority != null, [fieldsByIssueType]); - - const hasParent = useMemo(() => fieldsByIssueType.parent != null, [fieldsByIssueType]); - - const prioritiesSelectOptions = useMemo(() => { - const priorities = fieldsByIssueType.priority?.allowedValues ?? []; - return map( - (p) => ({ - text: p.name, - value: p.name, - }), - priorities - ); - }, [fieldsByIssueType]); - - const listItems = useMemo( - () => [ - ...(issueType != null && issueType.length > 0 - ? [ - { - title: i18n.ISSUE_TYPE, - description: issueTypes.find((issue) => issue.id === issueType)?.name ?? '', - }, - ] - : []), - ...(parent != null && parent.length > 0 - ? [ - { - title: i18n.PARENT_ISSUE, - description: parent, - }, - ] - : []), - ...(priority != null && priority.length > 0 - ? [ - { - title: i18n.PRIORITY, - description: priority, - }, - ] - : []), - ], - [issueType, issueTypes, parent, priority] - ); - - const onFieldChange = useCallback( - (key, value) => { - if (key === 'issueType') { - return onChange({ ...fields, issueType: value, priority: null, parent: null }); - } - return onChange({ - ...fields, - issueType: currentIssueType, - parent, - priority, - [key]: value, - }); - }, - [currentIssueType, fields, onChange, parent, priority] - ); - - // Set field at initialization - useEffect(() => { - if (init.current) { - init.current = false; - onChange({ issueType, priority, parent }); - } - }, [issueType, onChange, parent, priority]); - - return isEdit ? ( -
- - onFieldChange('issueType', e.target.value)} - options={issueTypesSelectOptions} - value={currentIssueType ?? ''} - /> - - - <> - {hasParent && ( - <> - - - - onFieldChange('parent', parentIssueKey)} - selectedValue={parent} - /> - - - - - - )} - {hasPriority && ( - <> - - - - onFieldChange('priority', e.target.value)} - options={prioritiesSelectOptions} - value={priority ?? ''} - /> - - - - - )} - -
- ) : ( - - ); -}; - -// eslint-disable-next-line import/no-default-export -export { JiraFieldsComponent as default }; diff --git a/x-pack/plugins/cases/public/components/connectors/jira/index.ts b/x-pack/plugins/cases/public/components/connectors/jira/index.ts deleted file mode 100644 index ea408a1bd666..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/jira/index.ts +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { lazy } from 'react'; - -import { CaseConnector } from '../types'; -import { JiraFieldsType } from '../../../../common'; -import * as i18n from './translations'; - -export * from './types'; - -export const getCaseConnector = (): CaseConnector => { - return { - id: '.jira', - fieldsComponent: lazy(() => import('./case_fields')), - }; -}; - -export const fieldLabels = { - issueType: i18n.ISSUE_TYPE, - priority: i18n.PRIORITY, - parent: i18n.PARENT_ISSUE, -}; diff --git a/x-pack/plugins/cases/public/components/connectors/jira/search_issues.tsx b/x-pack/plugins/cases/public/components/connectors/jira/search_issues.tsx deleted file mode 100644 index 9270abed0881..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/jira/search_issues.tsx +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { useMemo, useEffect, useCallback, useState, memo } from 'react'; -import { EuiComboBox, EuiComboBoxOptionOption } from '@elastic/eui'; - -import { useKibana } from '../../../common/lib/kibana'; -import { ActionConnector } from '../../../containers/types'; -import { useGetIssues } from './use_get_issues'; -import { useGetSingleIssue } from './use_get_single_issue'; -import * as i18n from './translations'; - -interface Props { - selectedValue: string | null; - actionConnector?: ActionConnector; - onChange: (parentIssueKey: string) => void; -} - -const SearchIssuesComponent: React.FC = ({ selectedValue, actionConnector, onChange }) => { - const [query, setQuery] = useState(null); - const [selectedOptions, setSelectedOptions] = useState>>( - [] - ); - const [options, setOptions] = useState>>([]); - const { http, notifications } = useKibana().services; - - const { isLoading: isLoadingIssues, issues } = useGetIssues({ - http, - toastNotifications: notifications.toasts, - actionConnector, - query, - }); - - const { isLoading: isLoadingSingleIssue, issue: singleIssue } = useGetSingleIssue({ - http, - toastNotifications: notifications.toasts, - actionConnector, - id: selectedValue, - }); - - useEffect(() => setOptions(issues.map((issue) => ({ label: issue.title, value: issue.key }))), [ - issues, - ]); - - useEffect(() => { - if (isLoadingSingleIssue || singleIssue == null) { - return; - } - - const singleIssueAsOptions = [{ label: singleIssue.title, value: singleIssue.key }]; - setOptions(singleIssueAsOptions); - setSelectedOptions(singleIssueAsOptions); - }, [singleIssue, isLoadingSingleIssue]); - - const onSearchChange = useCallback((searchVal: string) => { - setQuery(searchVal); - }, []); - - const onChangeComboBox = useCallback( - (changedOptions) => { - setSelectedOptions(changedOptions); - onChange(changedOptions[0].value); - }, - [onChange] - ); - - const inputPlaceholder = useMemo( - (): string => - isLoadingIssues || isLoadingSingleIssue - ? i18n.SEARCH_ISSUES_LOADING - : i18n.SEARCH_ISSUES_PLACEHOLDER, - [isLoadingIssues, isLoadingSingleIssue] - ); - - return ( - - ); -}; - -export const SearchIssues = memo(SearchIssuesComponent); diff --git a/x-pack/plugins/cases/public/components/connectors/jira/translations.ts b/x-pack/plugins/cases/public/components/connectors/jira/translations.ts deleted file mode 100644 index 88dd7d0c7c27..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/jira/translations.ts +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; - -export const ISSUE_TYPES_API_ERROR = i18n.translate( - 'xpack.cases.connectors.jira.unableToGetIssueTypesMessage', - { - defaultMessage: 'Unable to get issue types', - } -); - -export const FIELDS_API_ERROR = i18n.translate( - 'xpack.cases.connectors.jira.unableToGetFieldsMessage', - { - defaultMessage: 'Unable to get connectors', - } -); - -export const ISSUES_API_ERROR = i18n.translate( - 'xpack.cases.connectors.jira.unableToGetIssuesMessage', - { - defaultMessage: 'Unable to get issues', - } -); - -export const GET_ISSUE_API_ERROR = (id: string) => - i18n.translate('xpack.cases.connectors.jira.unableToGetIssueMessage', { - defaultMessage: 'Unable to get issue with id {id}', - values: { id }, - }); - -export const SEARCH_ISSUES_COMBO_BOX_ARIA_LABEL = i18n.translate( - 'xpack.cases.connectors.jira.searchIssuesComboBoxAriaLabel', - { - defaultMessage: 'Type to search', - } -); - -export const SEARCH_ISSUES_PLACEHOLDER = i18n.translate( - 'xpack.cases.connectors.jira.searchIssuesComboBoxPlaceholder', - { - defaultMessage: 'Type to search', - } -); - -export const SEARCH_ISSUES_LOADING = i18n.translate( - 'xpack.cases.connectors.jira.searchIssuesLoading', - { - defaultMessage: 'Loading...', - } -); - -export const PRIORITY = i18n.translate('xpack.cases.connectors.jira.prioritySelectFieldLabel', { - defaultMessage: 'Priority', -}); - -export const ISSUE_TYPE = i18n.translate('xpack.cases.connectors.jira.issueTypesSelectFieldLabel', { - defaultMessage: 'Issue type', -}); - -export const PARENT_ISSUE = i18n.translate('xpack.cases.connectors.jira.parentIssueSearchLabel', { - defaultMessage: 'Parent issue', -}); diff --git a/x-pack/plugins/cases/public/components/connectors/jira/types.ts b/x-pack/plugins/cases/public/components/connectors/jira/types.ts deleted file mode 100644 index 76c08a852c67..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/jira/types.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export type IssueTypes = Array<{ id: string; name: string }>; -export interface Fields { - [key: string]: { - allowedValues: Array<{ name: string; id: string }> | []; - defaultValue: { name: string; id: string } | {}; - }; -} - -export interface Issue { - id: string; - key: string; - title: string; -} - -export type Issues = Issue[]; diff --git a/x-pack/plugins/cases/public/components/connectors/jira/use_get_fields_by_issue_type.test.tsx b/x-pack/plugins/cases/public/components/connectors/jira/use_get_fields_by_issue_type.test.tsx deleted file mode 100644 index b4c2c848d79e..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/jira/use_get_fields_by_issue_type.test.tsx +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { renderHook, act } from '@testing-library/react-hooks'; - -import { useKibana } from '../../../common/lib/kibana'; -import { connector } from '../mock'; -import { useGetFieldsByIssueType, UseGetFieldsByIssueType } from './use_get_fields_by_issue_type'; -import * as api from './api'; - -jest.mock('../../../common/lib/kibana'); -jest.mock('./api'); - -const useKibanaMock = useKibana as jest.Mocked; - -describe('useGetFieldsByIssueType', () => { - const { http, notifications } = useKibanaMock().services; - - test('init', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook(() => - useGetFieldsByIssueType({ http, toastNotifications: notifications.toasts, issueType: null }) - ); - await waitForNextUpdate(); - expect(result.current).toEqual({ isLoading: true, fields: {} }); - }); - }); - - test('does not fetch when issueType is not provided', async () => { - const spyOnGetFieldsByIssueType = jest.spyOn(api, 'getFieldsByIssueType'); - - await act(async () => { - const { result, waitForNextUpdate } = renderHook(() => - useGetFieldsByIssueType({ - http, - toastNotifications: notifications.toasts, - connector, - issueType: null, - }) - ); - - await waitForNextUpdate(); - await waitForNextUpdate(); - expect(spyOnGetFieldsByIssueType).not.toHaveBeenCalled(); - expect(result.current).toEqual({ isLoading: false, fields: {} }); - }); - }); - - test('fetch fields', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook(() => - useGetFieldsByIssueType({ - http, - toastNotifications: notifications.toasts, - connector, - issueType: 'Task', - }) - ); - await waitForNextUpdate(); - await waitForNextUpdate(); - expect(result.current).toEqual({ - isLoading: false, - fields: { - summary: { allowedValues: [], defaultValue: {} }, - priority: { - allowedValues: [ - { - name: 'Medium', - id: '3', - }, - ], - defaultValue: { name: 'Medium', id: '3' }, - }, - }, - }); - }); - }); - - test('unhappy path', async () => { - const spyOnGetCaseConfigure = jest.spyOn(api, 'getFieldsByIssueType'); - spyOnGetCaseConfigure.mockImplementation(() => { - throw new Error('Something went wrong'); - }); - - await act(async () => { - const { result, waitForNextUpdate } = renderHook(() => - useGetFieldsByIssueType({ - http, - toastNotifications: notifications.toasts, - connector, - issueType: null, - }) - ); - - await waitForNextUpdate(); - await waitForNextUpdate(); - - expect(result.current).toEqual({ isLoading: false, fields: {} }); - }); - }); -}); diff --git a/x-pack/plugins/cases/public/components/connectors/jira/use_get_fields_by_issue_type.tsx b/x-pack/plugins/cases/public/components/connectors/jira/use_get_fields_by_issue_type.tsx deleted file mode 100644 index 03000e891661..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/jira/use_get_fields_by_issue_type.tsx +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { useState, useEffect, useRef } from 'react'; -import { HttpSetup, ToastsApi } from 'kibana/public'; -import { ActionConnector } from '../../../containers/types'; -import { getFieldsByIssueType } from './api'; -import { Fields } from './types'; -import * as i18n from './translations'; - -interface Props { - http: HttpSetup; - toastNotifications: Pick< - ToastsApi, - 'get$' | 'add' | 'remove' | 'addSuccess' | 'addWarning' | 'addDanger' | 'addError' - >; - issueType: string | null; - connector?: ActionConnector; -} - -export interface UseGetFieldsByIssueType { - fields: Fields; - isLoading: boolean; -} - -export const useGetFieldsByIssueType = ({ - http, - toastNotifications, - connector, - issueType, -}: Props): UseGetFieldsByIssueType => { - const [isLoading, setIsLoading] = useState(true); - const [fields, setFields] = useState({}); - const didCancel = useRef(false); - const abortCtrl = useRef(new AbortController()); - - useEffect(() => { - const fetchData = async () => { - if (!connector || !issueType) { - setIsLoading(false); - return; - } - - try { - abortCtrl.current = new AbortController(); - setIsLoading(true); - - const res = await getFieldsByIssueType({ - http, - signal: abortCtrl.current.signal, - connectorId: connector.id, - id: issueType, - }); - - if (!didCancel.current) { - setIsLoading(false); - setFields(res.data ?? {}); - if (res.status && res.status === 'error') { - toastNotifications.addDanger({ - title: i18n.FIELDS_API_ERROR, - text: `${res.serviceMessage ?? res.message}`, - }); - } - } - } catch (error) { - if (!didCancel.current) { - setIsLoading(false); - if (error.name !== 'AbortError') { - toastNotifications.addDanger({ - title: i18n.FIELDS_API_ERROR, - text: error.message, - }); - } - } - } - }; - - didCancel.current = false; - abortCtrl.current.abort(); - fetchData(); - - return () => { - didCancel.current = true; - abortCtrl.current.abort(); - }; - }, [http, connector, issueType, toastNotifications]); - - return { - isLoading, - fields, - }; -}; diff --git a/x-pack/plugins/cases/public/components/connectors/jira/use_get_issue_types.test.tsx b/x-pack/plugins/cases/public/components/connectors/jira/use_get_issue_types.test.tsx deleted file mode 100644 index 6c1a9b5fcab0..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/jira/use_get_issue_types.test.tsx +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { renderHook, act } from '@testing-library/react-hooks'; - -import { useKibana } from '../../../common/lib/kibana'; -import { connector } from '../mock'; -import { useGetIssueTypes, UseGetIssueTypes } from './use_get_issue_types'; -import * as api from './api'; - -jest.mock('../../../common/lib/kibana'); -jest.mock('./api'); - -const useKibanaMock = useKibana as jest.Mocked; - -describe('useGetIssueTypes', () => { - const { http, notifications } = useKibanaMock().services; - const handleIssueType = jest.fn(); - - beforeEach(() => jest.clearAllMocks()); - - test('init', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook(() => - useGetIssueTypes({ http, toastNotifications: notifications.toasts, handleIssueType }) - ); - await waitForNextUpdate(); - expect(result.current).toEqual({ isLoading: true, issueTypes: [] }); - }); - }); - - test('fetch issue types', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook(() => - useGetIssueTypes({ - http, - toastNotifications: notifications.toasts, - connector, - handleIssueType, - }) - ); - await waitForNextUpdate(); - await waitForNextUpdate(); - expect(result.current).toEqual({ - isLoading: false, - issueTypes: [ - { - id: '10006', - name: 'Task', - }, - { - id: '10007', - name: 'Bug', - }, - ], - }); - }); - }); - - test('handleIssueType is called', async () => { - await act(async () => { - const { waitForNextUpdate } = renderHook(() => - useGetIssueTypes({ - http, - toastNotifications: notifications.toasts, - connector, - handleIssueType, - }) - ); - - await waitForNextUpdate(); - await waitForNextUpdate(); - - expect(handleIssueType).toHaveBeenCalledWith([ - { text: 'Task', value: '10006' }, - { text: 'Bug', value: '10007' }, - ]); - }); - }); - - test('unhappy path', async () => { - const spyOnGetCaseConfigure = jest.spyOn(api, 'getIssueTypes'); - spyOnGetCaseConfigure.mockImplementation(() => { - throw new Error('Something went wrong'); - }); - - await act(async () => { - const { result, waitForNextUpdate } = renderHook(() => - useGetIssueTypes({ - http, - toastNotifications: notifications.toasts, - connector, - handleIssueType, - }) - ); - - await waitForNextUpdate(); - await waitForNextUpdate(); - - expect(result.current).toEqual({ isLoading: false, issueTypes: [] }); - }); - }); -}); diff --git a/x-pack/plugins/cases/public/components/connectors/jira/use_get_issue_types.tsx b/x-pack/plugins/cases/public/components/connectors/jira/use_get_issue_types.tsx deleted file mode 100644 index 3c35d315a2bc..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/jira/use_get_issue_types.tsx +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { useState, useEffect, useRef } from 'react'; -import { HttpSetup, ToastsApi } from 'kibana/public'; -import { ActionConnector } from '../../../containers/types'; -import { getIssueTypes } from './api'; -import { IssueTypes } from './types'; -import * as i18n from './translations'; - -interface Props { - http: HttpSetup; - toastNotifications: Pick< - ToastsApi, - 'get$' | 'add' | 'remove' | 'addSuccess' | 'addWarning' | 'addDanger' | 'addError' - >; - connector?: ActionConnector; - handleIssueType: (options: Array<{ value: string; text: string }>) => void; -} - -export interface UseGetIssueTypes { - issueTypes: IssueTypes; - isLoading: boolean; -} - -export const useGetIssueTypes = ({ - http, - connector, - toastNotifications, - handleIssueType, -}: Props): UseGetIssueTypes => { - const [isLoading, setIsLoading] = useState(true); - const [issueTypes, setIssueTypes] = useState([]); - const didCancel = useRef(false); - const abortCtrl = useRef(new AbortController()); - - useEffect(() => { - const fetchData = async () => { - if (!connector) { - setIsLoading(false); - return; - } - - try { - abortCtrl.current = new AbortController(); - setIsLoading(true); - - const res = await getIssueTypes({ - http, - signal: abortCtrl.current.signal, - connectorId: connector.id, - }); - - if (!didCancel.current) { - setIsLoading(false); - const asOptions = (res.data ?? []).map((type) => ({ - text: type.name ?? '', - value: type.id ?? '', - })); - setIssueTypes(res.data ?? []); - handleIssueType(asOptions); - if (res.status && res.status === 'error') { - toastNotifications.addDanger({ - title: i18n.ISSUE_TYPES_API_ERROR, - text: `${res.serviceMessage ?? res.message}`, - }); - } - } - } catch (error) { - if (!didCancel.current) { - setIsLoading(false); - if (error.name !== 'AbortError') { - toastNotifications.addDanger({ - title: i18n.ISSUE_TYPES_API_ERROR, - text: error.message, - }); - } - } - } - }; - - didCancel.current = false; - abortCtrl.current.abort(); - fetchData(); - - return () => { - didCancel.current = true; - abortCtrl.current.abort(); - }; - // handleIssueType unmounts the component at init causing the request to be aborted - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [http, connector, toastNotifications]); - - return { - issueTypes, - isLoading, - }; -}; diff --git a/x-pack/plugins/cases/public/components/connectors/jira/use_get_issues.test.tsx b/x-pack/plugins/cases/public/components/connectors/jira/use_get_issues.test.tsx deleted file mode 100644 index 2308fe604e71..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/jira/use_get_issues.test.tsx +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { renderHook, act } from '@testing-library/react-hooks'; - -import { useKibana } from '../../../common/lib/kibana'; -import { connector as actionConnector, issues } from '../mock'; -import { useGetIssues, UseGetIssues } from './use_get_issues'; -import * as api from './api'; - -jest.mock('../../../common/lib/kibana'); -jest.mock('./api'); - -const useKibanaMock = useKibana as jest.Mocked; - -describe('useGetIssues', () => { - const { http, notifications } = useKibanaMock().services; - beforeEach(() => jest.clearAllMocks()); - - test('init', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook(() => - useGetIssues({ - http, - toastNotifications: notifications.toasts, - actionConnector, - query: null, - }) - ); - await waitForNextUpdate(); - expect(result.current).toEqual({ isLoading: false, issues: [] }); - }); - }); - - test('fetch issues', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook(() => - useGetIssues({ - http, - toastNotifications: notifications.toasts, - actionConnector, - query: 'Task', - }) - ); - await waitForNextUpdate(); - await waitForNextUpdate(); - expect(result.current).toEqual({ - isLoading: false, - issues, - }); - }); - }); - - test('unhappy path', async () => { - const spyOnGetCaseConfigure = jest.spyOn(api, 'getIssues'); - spyOnGetCaseConfigure.mockImplementation(() => { - throw new Error('Something went wrong'); - }); - - await act(async () => { - const { result, waitForNextUpdate } = renderHook(() => - useGetIssues({ - http, - toastNotifications: notifications.toasts, - actionConnector, - query: 'oh no', - }) - ); - - await waitForNextUpdate(); - await waitForNextUpdate(); - - expect(result.current).toEqual({ isLoading: false, issues: [] }); - }); - }); -}); diff --git a/x-pack/plugins/cases/public/components/connectors/jira/use_get_issues.tsx b/x-pack/plugins/cases/public/components/connectors/jira/use_get_issues.tsx deleted file mode 100644 index b44b0558f153..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/jira/use_get_issues.tsx +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { isEmpty, debounce } from 'lodash/fp'; -import { useState, useEffect, useRef } from 'react'; -import { HttpSetup, ToastsApi } from 'kibana/public'; -import { ActionConnector } from '../../../containers/types'; -import { getIssues } from './api'; -import { Issues } from './types'; -import * as i18n from './translations'; - -interface Props { - http: HttpSetup; - toastNotifications: Pick< - ToastsApi, - 'get$' | 'add' | 'remove' | 'addSuccess' | 'addWarning' | 'addDanger' | 'addError' - >; - actionConnector?: ActionConnector; - query: string | null; -} - -export interface UseGetIssues { - issues: Issues; - isLoading: boolean; -} - -export const useGetIssues = ({ - http, - actionConnector, - toastNotifications, - query, -}: Props): UseGetIssues => { - const [isLoading, setIsLoading] = useState(false); - const [issues, setIssues] = useState([]); - const didCancel = useRef(false); - const abortCtrl = useRef(new AbortController()); - - useEffect(() => { - const fetchData = debounce(500, async () => { - if (!actionConnector || isEmpty(query)) { - setIsLoading(false); - return; - } - - try { - abortCtrl.current = new AbortController(); - setIsLoading(true); - - const res = await getIssues({ - http, - signal: abortCtrl.current.signal, - connectorId: actionConnector.id, - title: query ?? '', - }); - - if (!didCancel.current) { - setIsLoading(false); - setIssues(res.data ?? []); - if (res.status && res.status === 'error') { - toastNotifications.addDanger({ - title: i18n.ISSUES_API_ERROR, - text: `${res.serviceMessage ?? res.message}`, - }); - } - } - } catch (error) { - if (!didCancel.current) { - setIsLoading(false); - if (error.name !== 'AbortError') { - toastNotifications.addDanger({ - title: i18n.ISSUES_API_ERROR, - text: error.message, - }); - } - } - } - }); - - didCancel.current = false; - abortCtrl.current.abort(); - fetchData(); - - return () => { - didCancel.current = true; - abortCtrl.current.abort(); - }; - }, [http, actionConnector, toastNotifications, query]); - - return { - issues, - isLoading, - }; -}; diff --git a/x-pack/plugins/cases/public/components/connectors/jira/use_get_single_issue.test.tsx b/x-pack/plugins/cases/public/components/connectors/jira/use_get_single_issue.test.tsx deleted file mode 100644 index 28949b456ecd..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/jira/use_get_single_issue.test.tsx +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { renderHook, act } from '@testing-library/react-hooks'; - -import { useKibana } from '../../../common/lib/kibana'; -import { connector as actionConnector, issues } from '../mock'; -import { useGetSingleIssue, UseGetSingleIssue } from './use_get_single_issue'; -import * as api from './api'; - -jest.mock('../../../common/lib/kibana'); -jest.mock('./api'); - -const useKibanaMock = useKibana as jest.Mocked; - -describe('useGetSingleIssue', () => { - const { http, notifications } = useKibanaMock().services; - beforeEach(() => jest.clearAllMocks()); - - test('init', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook(() => - useGetSingleIssue({ - http, - toastNotifications: notifications.toasts, - actionConnector, - id: null, - }) - ); - await waitForNextUpdate(); - expect(result.current).toEqual({ isLoading: false, issue: null }); - }); - }); - - test('fetch issues', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook(() => - useGetSingleIssue({ - http, - toastNotifications: notifications.toasts, - actionConnector, - id: '123', - }) - ); - await waitForNextUpdate(); - await waitForNextUpdate(); - expect(result.current).toEqual({ - isLoading: false, - issue: issues[0], - }); - }); - }); - - test('unhappy path', async () => { - const spyOnGetCaseConfigure = jest.spyOn(api, 'getIssue'); - spyOnGetCaseConfigure.mockImplementation(() => { - throw new Error('Something went wrong'); - }); - - await act(async () => { - const { result, waitForNextUpdate } = renderHook(() => - useGetSingleIssue({ - http, - toastNotifications: notifications.toasts, - actionConnector, - id: '123', - }) - ); - - await waitForNextUpdate(); - await waitForNextUpdate(); - - expect(result.current).toEqual({ isLoading: false, issue: null }); - }); - }); -}); diff --git a/x-pack/plugins/cases/public/components/connectors/jira/use_get_single_issue.tsx b/x-pack/plugins/cases/public/components/connectors/jira/use_get_single_issue.tsx deleted file mode 100644 index 6c7028642616..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/jira/use_get_single_issue.tsx +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { useState, useEffect, useRef } from 'react'; -import { HttpSetup, ToastsApi } from 'kibana/public'; -import { ActionConnector } from '../../../containers/types'; -import { getIssue } from './api'; -import { Issue } from './types'; -import * as i18n from './translations'; - -interface Props { - http: HttpSetup; - toastNotifications: Pick< - ToastsApi, - 'get$' | 'add' | 'remove' | 'addSuccess' | 'addWarning' | 'addDanger' | 'addError' - >; - id: string | null; - actionConnector?: ActionConnector; -} - -export interface UseGetSingleIssue { - issue: Issue | null; - isLoading: boolean; -} - -export const useGetSingleIssue = ({ - http, - toastNotifications, - actionConnector, - id, -}: Props): UseGetSingleIssue => { - const [isLoading, setIsLoading] = useState(false); - const [issue, setIssue] = useState(null); - const didCancel = useRef(false); - const abortCtrl = useRef(new AbortController()); - - useEffect(() => { - const fetchData = async () => { - if (!actionConnector || !id) { - setIsLoading(false); - return; - } - - abortCtrl.current = new AbortController(); - setIsLoading(true); - try { - const res = await getIssue({ - http, - signal: abortCtrl.current.signal, - connectorId: actionConnector.id, - id, - }); - - if (!didCancel.current) { - setIsLoading(false); - setIssue(res.data ?? null); - if (res.status && res.status === 'error') { - toastNotifications.addDanger({ - title: i18n.GET_ISSUE_API_ERROR(id), - text: `${res.serviceMessage ?? res.message}`, - }); - } - } - } catch (error) { - if (!didCancel.current) { - setIsLoading(false); - if (error.name !== 'AbortError') { - toastNotifications.addDanger({ - title: i18n.GET_ISSUE_API_ERROR(id), - text: error.message, - }); - } - } - } - }; - - didCancel.current = false; - abortCtrl.current.abort(); - fetchData(); - - return () => { - didCancel.current = true; - abortCtrl.current.abort(); - }; - }, [http, actionConnector, id, toastNotifications]); - - return { - isLoading, - issue, - }; -}; diff --git a/x-pack/plugins/cases/public/components/connectors/mock.ts b/x-pack/plugins/cases/public/components/connectors/mock.ts deleted file mode 100644 index f5429fa2396a..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/mock.ts +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export const connector = { - id: '123', - name: 'My connector', - actionTypeId: '.jira', - config: {}, - isPreconfigured: false, -}; - -export const issues = [ - { id: 'personId', title: 'Person Task', key: 'personKey' }, - { id: 'womanId', title: 'Woman Task', key: 'womanKey' }, - { id: 'manId', title: 'Man Task', key: 'manKey' }, - { id: 'cameraId', title: 'Camera Task', key: 'cameraKey' }, - { id: 'tvId', title: 'TV Task', key: 'tvKey' }, -]; - -export const choices = [ - { - dependent_value: '', - label: 'Priviledge Escalation', - value: 'Priviledge Escalation', - element: 'category', - }, - { - dependent_value: '', - label: 'Criminal activity/investigation', - value: 'Criminal activity/investigation', - element: 'category', - }, - { - dependent_value: '', - label: 'Denial of Service', - value: 'Denial of Service', - element: 'category', - }, - { - dependent_value: 'Denial of Service', - label: 'Inbound or outbound', - value: '12', - element: 'subcategory', - }, - { - dependent_value: 'Denial of Service', - label: 'Single or distributed (DoS or DDoS)', - value: '26', - element: 'subcategory', - }, - { - dependent_value: 'Denial of Service', - label: 'Inbound DDos', - value: 'inbound_ddos', - element: 'subcategory', - }, - { - dependent_value: '', - label: 'Software', - value: 'software', - element: 'category', - }, - { - dependent_value: 'software', - label: 'Operation System', - value: 'os', - element: 'subcategory', - }, - ...['severity', 'urgency', 'impact', 'priority'] - .map((element) => [ - { - dependent_value: '', - label: '1 - Critical', - value: '1', - element, - }, - { - dependent_value: '', - label: '2 - High', - value: '2', - element, - }, - { - dependent_value: '', - label: '3 - Moderate', - value: '3', - element, - }, - { - dependent_value: '', - label: '4 - Low', - value: '4', - element, - }, - ]) - .flat(), -]; - -export const severity = [ - { - id: 4, - name: 'Low', - }, - { - id: 5, - name: 'Medium', - }, - { - id: 6, - name: 'High', - }, -]; - -export const incidentTypes = [ - { id: 17, name: 'Communication error (fax; email)' }, - { id: 1001, name: 'Custom type' }, -]; diff --git a/x-pack/plugins/cases/public/components/connectors/resilient/__mocks__/api.ts b/x-pack/plugins/cases/public/components/connectors/resilient/__mocks__/api.ts deleted file mode 100644 index c27248288907..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/resilient/__mocks__/api.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { incidentTypes, severity } from '../../mock'; -import { Props } from '../api'; -import { ResilientIncidentTypes, ResilientSeverity } from '../types'; - -export const getIncidentTypes = async (props: Props): Promise<{ data: ResilientIncidentTypes }> => - Promise.resolve({ data: incidentTypes }); - -export const getSeverity = async (props: Props): Promise<{ data: ResilientSeverity }> => - Promise.resolve({ data: severity }); diff --git a/x-pack/plugins/cases/public/components/connectors/resilient/api.ts b/x-pack/plugins/cases/public/components/connectors/resilient/api.ts deleted file mode 100644 index 5fec83f30395..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/resilient/api.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { HttpSetup } from 'kibana/public'; -import { ActionTypeExecutorResult } from '../../../../../actions/common'; -import { ResilientIncidentTypes, ResilientSeverity } from './types'; - -export const BASE_ACTION_API_PATH = '/api/actions'; - -export interface Props { - http: HttpSetup; - signal: AbortSignal; - connectorId: string; -} - -export async function getIncidentTypes({ http, signal, connectorId }: Props) { - return http.post>( - `${BASE_ACTION_API_PATH}/action/${connectorId}/_execute`, - { - body: JSON.stringify({ - params: { subAction: 'incidentTypes', subActionParams: {} }, - }), - signal, - } - ); -} - -export async function getSeverity({ http, signal, connectorId }: Props) { - return http.post>( - `${BASE_ACTION_API_PATH}/action/${connectorId}/_execute`, - { - body: JSON.stringify({ - params: { subAction: 'severity', subActionParams: {} }, - }), - signal, - } - ); -} diff --git a/x-pack/plugins/cases/public/components/connectors/resilient/case_fields.test.tsx b/x-pack/plugins/cases/public/components/connectors/resilient/case_fields.test.tsx deleted file mode 100644 index dda6ba5de95c..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/resilient/case_fields.test.tsx +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { mount } from 'enzyme'; -import { EuiComboBox, EuiComboBoxOptionOption } from '@elastic/eui'; -import { waitFor } from '@testing-library/react'; - -import { connector } from '../mock'; -import { useGetIncidentTypes } from './use_get_incident_types'; -import { useGetSeverity } from './use_get_severity'; -import Fields from './case_fields'; - -jest.mock('../../../common/lib/kibana'); -jest.mock('./use_get_incident_types'); -jest.mock('./use_get_severity'); - -const useGetIncidentTypesMock = useGetIncidentTypes as jest.Mock; -const useGetSeverityMock = useGetSeverity as jest.Mock; - -describe('ResilientParamsFields renders', () => { - const useGetIncidentTypesResponse = { - isLoading: false, - incidentTypes: [ - { - id: 19, - name: 'Malware', - }, - { - id: 21, - name: 'Denial of Service', - }, - ], - }; - - const useGetSeverityResponse = { - isLoading: false, - severity: [ - { - id: 4, - name: 'Low', - }, - { - id: 5, - name: 'Medium', - }, - { - id: 6, - name: 'High', - }, - ], - }; - - const fields = { - severityCode: '6', - incidentTypes: ['19'], - }; - - const onChange = jest.fn(); - - beforeEach(() => { - useGetIncidentTypesMock.mockReturnValue(useGetIncidentTypesResponse); - useGetSeverityMock.mockReturnValue(useGetSeverityResponse); - jest.clearAllMocks(); - }); - - test('all params fields are rendered', () => { - const wrapper = mount(); - expect(wrapper.find('[data-test-subj="incidentTypeComboBox"]').first().prop('options')).toEqual( - [ - { label: 'Malware', value: '19' }, - { label: 'Denial of Service', value: '21' }, - ] - ); - - expect( - wrapper.find('[data-test-subj="incidentTypeComboBox"]').first().prop('selectedOptions') - ).toEqual([{ label: 'Malware', value: '19' }]); - - expect(wrapper.find('[data-test-subj="severitySelect"]').first().prop('value')).toStrictEqual( - '6' - ); - }); - - test('it disabled the fields when loading incident types', () => { - useGetIncidentTypesMock.mockReturnValue({ ...useGetIncidentTypesResponse, isLoading: true }); - - const wrapper = mount(); - - expect( - wrapper.find('[data-test-subj="incidentTypeComboBox"]').first().prop('isDisabled') - ).toBeTruthy(); - }); - - test('it disabled the fields when loading severity', () => { - useGetSeverityMock.mockReturnValue({ - ...useGetSeverityResponse, - isLoading: true, - }); - - const wrapper = mount(); - - expect(wrapper.find('[data-test-subj="severitySelect"]').first().prop('disabled')).toBeTruthy(); - }); - - test('it sets issue type correctly', async () => { - const wrapper = mount(); - - await waitFor(() => { - ((wrapper.find(EuiComboBox).props() as unknown) as { - onChange: (a: EuiComboBoxOptionOption[]) => void; - }).onChange([{ value: '19', label: 'Denial of Service' }]); - }); - - expect(onChange).toHaveBeenCalledWith({ incidentTypes: ['19'], severityCode: '6' }); - }); - - test('it sets severity correctly', async () => { - const wrapper = mount(); - - wrapper - .find('select[data-test-subj="severitySelect"]') - .first() - .simulate('change', { - target: { value: '4' }, - }); - - expect(onChange).toHaveBeenCalledWith({ incidentTypes: ['19'], severityCode: '4' }); - }); -}); diff --git a/x-pack/plugins/cases/public/components/connectors/resilient/case_fields.tsx b/x-pack/plugins/cases/public/components/connectors/resilient/case_fields.tsx deleted file mode 100644 index e1eeb13bf684..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/resilient/case_fields.tsx +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { useMemo, useCallback, useEffect, useRef } from 'react'; -import { - EuiComboBox, - EuiComboBoxOptionOption, - EuiFormRow, - EuiSelect, - EuiSelectOption, - EuiSpacer, -} from '@elastic/eui'; - -import { useKibana } from '../../../common/lib/kibana'; -import { ConnectorFieldsProps } from '../types'; -import { useGetIncidentTypes } from './use_get_incident_types'; -import { useGetSeverity } from './use_get_severity'; - -import * as i18n from './translations'; -import { ConnectorTypes, ResilientFieldsType } from '../../../../common'; -import { ConnectorCard } from '../card'; - -const ResilientFieldsComponent: React.FunctionComponent< - ConnectorFieldsProps -> = ({ isEdit = true, fields, connector, onChange }) => { - const init = useRef(true); - const { incidentTypes = null, severityCode = null } = fields ?? {}; - - const { http, notifications } = useKibana().services; - - const { - isLoading: isLoadingIncidentTypes, - incidentTypes: allIncidentTypes, - } = useGetIncidentTypes({ - http, - toastNotifications: notifications.toasts, - connector, - }); - - const { isLoading: isLoadingSeverity, severity } = useGetSeverity({ - http, - toastNotifications: notifications.toasts, - connector, - }); - - const severitySelectOptions: EuiSelectOption[] = useMemo( - () => - severity.map((s) => ({ - value: s.id.toString(), - text: s.name, - })), - [severity] - ); - - const incidentTypesComboBoxOptions: Array> = useMemo( - () => - allIncidentTypes - ? allIncidentTypes.map((type: { id: number; name: string }) => ({ - label: type.name, - value: type.id.toString(), - })) - : [], - [allIncidentTypes] - ); - const listItems = useMemo( - () => [ - ...(incidentTypes != null && incidentTypes.length > 0 - ? [ - { - title: i18n.INCIDENT_TYPES_LABEL, - description: allIncidentTypes - .filter((type) => incidentTypes.includes(type.id.toString())) - .map((type) => type.name) - .join(', '), - }, - ] - : []), - ...(severityCode != null && severityCode.length > 0 - ? [ - { - title: i18n.SEVERITY_LABEL, - description: - severity.find((severityObj) => severityObj.id.toString() === severityCode)?.name ?? - '', - }, - ] - : []), - ], - [incidentTypes, severityCode, allIncidentTypes, severity] - ); - - const onFieldChange = useCallback( - (key, value) => { - onChange({ - ...fields, - incidentTypes, - severityCode, - [key]: value, - }); - }, - [incidentTypes, severityCode, onChange, fields] - ); - - const selectedIncidentTypesComboBoxOptionsMemo = useMemo(() => { - const allIncidentTypesAsObject = allIncidentTypes.reduce( - (acc, type) => ({ ...acc, [type.id.toString()]: type.name }), - {} as Record - ); - return incidentTypes - ? incidentTypes - .map((type) => ({ - label: allIncidentTypesAsObject[type.toString()], - value: type.toString(), - })) - .filter((type) => type.label != null) - : []; - }, [allIncidentTypes, incidentTypes]); - - const onIncidentChange = useCallback( - (selectedOptions: Array<{ label: string; value?: string }>) => { - onFieldChange( - 'incidentTypes', - selectedOptions.map((selectedOption) => selectedOption.value ?? selectedOption.label) - ); - }, - [onFieldChange] - ); - - const onIncidentBlur = useCallback(() => { - if (!incidentTypes) { - onFieldChange('incidentTypes', []); - } - }, [incidentTypes, onFieldChange]); - - // Set field at initialization - useEffect(() => { - if (init.current) { - init.current = false; - onChange({ incidentTypes, severityCode }); - } - }, [incidentTypes, onChange, severityCode]); - - return isEdit ? ( - - - - - - - onFieldChange('severityCode', e.target.value)} - options={severitySelectOptions} - value={severityCode ?? undefined} - /> - - - - ) : ( - - ); -}; - -// eslint-disable-next-line import/no-default-export -export { ResilientFieldsComponent as default }; diff --git a/x-pack/plugins/cases/public/components/connectors/resilient/index.ts b/x-pack/plugins/cases/public/components/connectors/resilient/index.ts deleted file mode 100644 index c8e7ad9a063c..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/resilient/index.ts +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { lazy } from 'react'; - -import { CaseConnector } from '../types'; -import { ResilientFieldsType } from '../../../../common'; -import * as i18n from './translations'; - -export * from './types'; - -export const getCaseConnector = (): CaseConnector => { - return { - id: '.resilient', - fieldsComponent: lazy(() => import('./case_fields')), - }; -}; - -export const fieldLabels = { - incidentTypes: i18n.INCIDENT_TYPES_LABEL, - severityCode: i18n.SEVERITY_LABEL, -}; diff --git a/x-pack/plugins/cases/public/components/connectors/resilient/translations.ts b/x-pack/plugins/cases/public/components/connectors/resilient/translations.ts deleted file mode 100644 index 1b63a5098e92..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/resilient/translations.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; - -export const INCIDENT_TYPES_API_ERROR = i18n.translate( - 'xpack.cases.connectors.resilient.unableToGetIncidentTypesMessage', - { - defaultMessage: 'Unable to get incident types', - } -); - -export const SEVERITY_API_ERROR = i18n.translate( - 'xpack.cases.connectors.resilient.unableToGetSeverityMessage', - { - defaultMessage: 'Unable to get severity', - } -); - -export const INCIDENT_TYPES_PLACEHOLDER = i18n.translate( - 'xpack.cases.connectors.resilient.incidentTypesPlaceholder', - { - defaultMessage: 'Choose types', - } -); - -export const INCIDENT_TYPES_LABEL = i18n.translate( - 'xpack.cases.connectors.resilient.incidentTypesLabel', - { - defaultMessage: 'Incident Types', - } -); - -export const SEVERITY_LABEL = i18n.translate('xpack.cases.connectors.resilient.severityLabel', { - defaultMessage: 'Severity', -}); diff --git a/x-pack/plugins/cases/public/components/connectors/resilient/types.ts b/x-pack/plugins/cases/public/components/connectors/resilient/types.ts deleted file mode 100644 index 06506d2c0d2f..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/resilient/types.ts +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export type ResilientIncidentTypes = Array<{ id: number; name: string }>; -export type ResilientSeverity = ResilientIncidentTypes; diff --git a/x-pack/plugins/cases/public/components/connectors/resilient/use_get_incident_types.test.tsx b/x-pack/plugins/cases/public/components/connectors/resilient/use_get_incident_types.test.tsx deleted file mode 100644 index 59c1f8e9b40d..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/resilient/use_get_incident_types.test.tsx +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { renderHook, act } from '@testing-library/react-hooks'; - -import { useKibana } from '../../../common/lib/kibana'; -import { connector } from '../mock'; -import { useGetIncidentTypes, UseGetIncidentTypes } from './use_get_incident_types'; -import * as api from './api'; - -jest.mock('../../../common/lib/kibana'); -jest.mock('./api'); - -const useKibanaMock = useKibana as jest.Mocked; - -describe('useGetIncidentTypes', () => { - const { http, notifications } = useKibanaMock().services; - - test('init', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook(() => - useGetIncidentTypes({ http, toastNotifications: notifications.toasts }) - ); - await waitForNextUpdate(); - expect(result.current).toEqual({ isLoading: true, incidentTypes: [] }); - }); - }); - - test('fetch incident types', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook(() => - useGetIncidentTypes({ - http, - toastNotifications: notifications.toasts, - connector, - }) - ); - await waitForNextUpdate(); - await waitForNextUpdate(); - expect(result.current).toEqual({ - isLoading: false, - incidentTypes: [ - { id: 17, name: 'Communication error (fax; email)' }, - { id: 1001, name: 'Custom type' }, - ], - }); - }); - }); - - test('unhappy path', async () => { - const spyOnGetCaseConfigure = jest.spyOn(api, 'getIncidentTypes'); - spyOnGetCaseConfigure.mockImplementation(() => { - throw new Error('Something went wrong'); - }); - - await act(async () => { - const { result, waitForNextUpdate } = renderHook(() => - useGetIncidentTypes({ http, toastNotifications: notifications.toasts, connector }) - ); - - await waitForNextUpdate(); - await waitForNextUpdate(); - - expect(result.current).toEqual({ isLoading: false, incidentTypes: [] }); - }); - }); -}); diff --git a/x-pack/plugins/cases/public/components/connectors/resilient/use_get_incident_types.tsx b/x-pack/plugins/cases/public/components/connectors/resilient/use_get_incident_types.tsx deleted file mode 100644 index 34cbb0a69b0f..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/resilient/use_get_incident_types.tsx +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { useState, useEffect, useRef } from 'react'; -import { HttpSetup, ToastsApi } from 'kibana/public'; -import { ActionConnector } from '../../../containers/types'; -import { getIncidentTypes } from './api'; -import * as i18n from './translations'; - -type IncidentTypes = Array<{ id: number; name: string }>; - -interface Props { - http: HttpSetup; - toastNotifications: Pick< - ToastsApi, - 'get$' | 'add' | 'remove' | 'addSuccess' | 'addWarning' | 'addDanger' | 'addError' - >; - connector?: ActionConnector; -} - -export interface UseGetIncidentTypes { - incidentTypes: IncidentTypes; - isLoading: boolean; -} - -export const useGetIncidentTypes = ({ - http, - toastNotifications, - connector, -}: Props): UseGetIncidentTypes => { - const [isLoading, setIsLoading] = useState(true); - const [incidentTypes, setIncidentTypes] = useState([]); - const didCancel = useRef(false); - const abortCtrl = useRef(new AbortController()); - - useEffect(() => { - const fetchData = async () => { - if (!connector) { - setIsLoading(false); - return; - } - - try { - abortCtrl.current = new AbortController(); - setIsLoading(true); - - const res = await getIncidentTypes({ - http, - signal: abortCtrl.current.signal, - connectorId: connector.id, - }); - - if (!didCancel.current) { - setIsLoading(false); - setIncidentTypes(res.data ?? []); - if (res.status && res.status === 'error') { - toastNotifications.addDanger({ - title: i18n.INCIDENT_TYPES_API_ERROR, - text: `${res.serviceMessage ?? res.message}`, - }); - } - } - } catch (error) { - if (!didCancel.current) { - setIsLoading(false); - if (error.name !== 'AbortError') { - toastNotifications.addDanger({ - title: i18n.INCIDENT_TYPES_API_ERROR, - text: error.message, - }); - } - } - } - }; - - didCancel.current = false; - abortCtrl.current.abort(); - fetchData(); - - return () => { - didCancel.current = true; - abortCtrl.current.abort(); - }; - }, [http, connector, toastNotifications]); - - return { - incidentTypes, - isLoading, - }; -}; diff --git a/x-pack/plugins/cases/public/components/connectors/resilient/use_get_severity.test.tsx b/x-pack/plugins/cases/public/components/connectors/resilient/use_get_severity.test.tsx deleted file mode 100644 index f646dd7e8f7c..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/resilient/use_get_severity.test.tsx +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { renderHook, act } from '@testing-library/react-hooks'; - -import { useKibana } from '../../../common/lib/kibana'; -import { connector } from '../mock'; -import { useGetSeverity, UseGetSeverity } from './use_get_severity'; -import * as api from './api'; - -jest.mock('../../../common/lib/kibana'); -jest.mock('./api'); - -const useKibanaMock = useKibana as jest.Mocked; - -describe('useGetSeverity', () => { - const { http, notifications } = useKibanaMock().services; - - test('init', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook(() => - useGetSeverity({ http, toastNotifications: notifications.toasts }) - ); - await waitForNextUpdate(); - expect(result.current).toEqual({ isLoading: true, severity: [] }); - }); - }); - - test('fetch severity', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook(() => - useGetSeverity({ http, toastNotifications: notifications.toasts, connector }) - ); - await waitForNextUpdate(); - await waitForNextUpdate(); - expect(result.current).toEqual({ - isLoading: false, - severity: [ - { - id: 4, - name: 'Low', - }, - { - id: 5, - name: 'Medium', - }, - { - id: 6, - name: 'High', - }, - ], - }); - }); - }); - - test('unhappy path', async () => { - const spyOnGetCaseConfigure = jest.spyOn(api, 'getSeverity'); - spyOnGetCaseConfigure.mockImplementation(() => { - throw new Error('Something went wrong'); - }); - - await act(async () => { - const { result, waitForNextUpdate } = renderHook(() => - useGetSeverity({ http, toastNotifications: notifications.toasts, connector }) - ); - - await waitForNextUpdate(); - await waitForNextUpdate(); - - expect(result.current).toEqual({ isLoading: false, severity: [] }); - }); - }); -}); diff --git a/x-pack/plugins/cases/public/components/connectors/resilient/use_get_severity.tsx b/x-pack/plugins/cases/public/components/connectors/resilient/use_get_severity.tsx deleted file mode 100644 index 5b44c6b4a32b..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/resilient/use_get_severity.tsx +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { useState, useEffect, useRef } from 'react'; -import { HttpSetup, ToastsApi } from 'kibana/public'; -import { ActionConnector } from '../../../containers/types'; -import { getSeverity } from './api'; -import * as i18n from './translations'; - -type Severity = Array<{ id: number; name: string }>; - -interface Props { - http: HttpSetup; - toastNotifications: Pick< - ToastsApi, - 'get$' | 'add' | 'remove' | 'addSuccess' | 'addWarning' | 'addDanger' | 'addError' - >; - connector?: ActionConnector; -} - -export interface UseGetSeverity { - severity: Severity; - isLoading: boolean; -} - -export const useGetSeverity = ({ http, toastNotifications, connector }: Props): UseGetSeverity => { - const [isLoading, setIsLoading] = useState(true); - const [severity, setSeverity] = useState([]); - const abortCtrl = useRef(new AbortController()); - const didCancel = useRef(false); - - useEffect(() => { - const fetchData = async () => { - if (!connector) { - setIsLoading(false); - return; - } - - try { - abortCtrl.current = new AbortController(); - setIsLoading(true); - - const res = await getSeverity({ - http, - signal: abortCtrl.current.signal, - connectorId: connector.id, - }); - - if (!didCancel.current) { - setIsLoading(false); - setSeverity(res.data ?? []); - - if (res.status && res.status === 'error') { - toastNotifications.addDanger({ - title: i18n.SEVERITY_API_ERROR, - text: `${res.serviceMessage ?? res.message}`, - }); - } - } - } catch (error) { - if (!didCancel.current) { - setIsLoading(false); - if (error.name !== 'AbortError') { - toastNotifications.addDanger({ - title: i18n.SEVERITY_API_ERROR, - text: error.message, - }); - } - } - } - }; - - didCancel.current = false; - abortCtrl.current.abort(); - fetchData(); - - return () => { - didCancel.current = true; - abortCtrl.current.abort(); - }; - }, [http, connector, toastNotifications]); - - return { - severity, - isLoading, - }; -}; diff --git a/x-pack/plugins/cases/public/components/connectors/servicenow/__mocks__/api.ts b/x-pack/plugins/cases/public/components/connectors/servicenow/__mocks__/api.ts deleted file mode 100644 index 215e3d6f92e6..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/servicenow/__mocks__/api.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { choices } from '../../mock'; -import { GetChoicesProps } from '../api'; -import { Choice } from '../types'; - -export const choicesResponse = { - status: 'ok', - data: choices, -}; - -export const getChoices = async ( - props: GetChoicesProps -): Promise<{ status: string; data: Choice[] }> => Promise.resolve(choicesResponse); diff --git a/x-pack/plugins/cases/public/components/connectors/servicenow/api.test.ts b/x-pack/plugins/cases/public/components/connectors/servicenow/api.test.ts deleted file mode 100644 index 461823036ed2..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/servicenow/api.test.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { httpServiceMock } from '../../../../../../../src/core/public/mocks'; -import { getChoices } from './api'; -import { choices } from '../mock'; - -const choicesResponse = { - status: 'ok', - data: choices, -}; - -describe('ServiceNow API', () => { - const http = httpServiceMock.createStartContract(); - - beforeEach(() => jest.resetAllMocks()); - - describe('getChoices', () => { - test('should call get choices API', async () => { - const abortCtrl = new AbortController(); - http.post.mockResolvedValueOnce(choicesResponse); - const res = await getChoices({ - http, - signal: abortCtrl.signal, - connectorId: 'test', - fields: ['priority'], - }); - - expect(res).toEqual(choicesResponse); - expect(http.post).toHaveBeenCalledWith('/api/actions/action/test/_execute', { - body: '{"params":{"subAction":"getChoices","subActionParams":{"fields":["priority"]}}}', - signal: abortCtrl.signal, - }); - }); - }); -}); diff --git a/x-pack/plugins/cases/public/components/connectors/servicenow/api.ts b/x-pack/plugins/cases/public/components/connectors/servicenow/api.ts deleted file mode 100644 index e68eb18860ae..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/servicenow/api.ts +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { HttpSetup } from 'kibana/public'; -import { ActionTypeExecutorResult } from '../../../../../actions/common'; -import { Choice } from './types'; - -export const BASE_ACTION_API_PATH = '/api/actions'; - -export interface GetChoicesProps { - http: HttpSetup; - signal: AbortSignal; - connectorId: string; - fields: string[]; -} - -export async function getChoices({ http, signal, connectorId, fields }: GetChoicesProps) { - return http.post>( - `${BASE_ACTION_API_PATH}/action/${connectorId}/_execute`, - { - body: JSON.stringify({ - params: { subAction: 'getChoices', subActionParams: { fields } }, - }), - signal, - } - ); -} diff --git a/x-pack/plugins/cases/public/components/connectors/servicenow/helpers.ts b/x-pack/plugins/cases/public/components/connectors/servicenow/helpers.ts deleted file mode 100644 index 314d22449112..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/servicenow/helpers.ts +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiSelectOption } from '@elastic/eui'; -import { Choice } from './types'; - -export const choicesToEuiOptions = (choices: Choice[]): EuiSelectOption[] => - choices.map((choice) => ({ value: choice.value, text: choice.label })); diff --git a/x-pack/plugins/cases/public/components/connectors/servicenow/index.ts b/x-pack/plugins/cases/public/components/connectors/servicenow/index.ts deleted file mode 100644 index a6f0795fe4d8..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/servicenow/index.ts +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { lazy } from 'react'; - -import { CaseConnector } from '../types'; -import { ServiceNowITSMFieldsType, ServiceNowSIRFieldsType } from '../../../../common'; -import * as i18n from './translations'; - -export const getServiceNowITSMCaseConnector = (): CaseConnector => { - return { - id: '.servicenow', - fieldsComponent: lazy(() => import('./servicenow_itsm_case_fields')), - }; -}; - -export const getServiceNowSIRCaseConnector = (): CaseConnector => { - return { - id: '.servicenow-sir', - fieldsComponent: lazy(() => import('./servicenow_sir_case_fields')), - }; -}; - -export const serviceNowITSMFieldLabels = { - impact: i18n.IMPACT, - severity: i18n.SEVERITY, - urgency: i18n.URGENCY, -}; diff --git a/x-pack/plugins/cases/public/components/connectors/servicenow/servicenow_itsm_case_fields.test.tsx b/x-pack/plugins/cases/public/components/connectors/servicenow/servicenow_itsm_case_fields.test.tsx deleted file mode 100644 index 9688ca191d67..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/servicenow/servicenow_itsm_case_fields.test.tsx +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { waitFor, act } from '@testing-library/react'; -import { EuiSelect } from '@elastic/eui'; -import { mount } from 'enzyme'; - -import { connector, choices as mockChoices } from '../mock'; -import { Choice } from './types'; -import Fields from './servicenow_itsm_case_fields'; - -let onChoicesSuccess = (c: Choice[]) => {}; - -jest.mock('../../../common/lib/kibana'); -jest.mock('./use_get_choices', () => ({ - useGetChoices: (args: { onSuccess: () => void }) => { - onChoicesSuccess = args.onSuccess; - return { isLoading: false, choices: mockChoices }; - }, -})); - -describe('ServiceNowITSM Fields', () => { - const fields = { - severity: '1', - urgency: '2', - impact: '3', - category: 'software', - subcategory: 'os', - }; - const onChange = jest.fn(); - - beforeEach(() => { - jest.clearAllMocks(); - }); - - it('all params fields are rendered - isEdit: true', () => { - const wrapper = mount(); - expect(wrapper.find('[data-test-subj="severitySelect"]').exists()).toBeTruthy(); - expect(wrapper.find('[data-test-subj="urgencySelect"]').exists()).toBeTruthy(); - expect(wrapper.find('[data-test-subj="impactSelect"]').exists()).toBeTruthy(); - expect(wrapper.find('[data-test-subj="categorySelect"]').exists()).toBeTruthy(); - expect(wrapper.find('[data-test-subj="subcategorySelect"]').exists()).toBeTruthy(); - }); - - it('all params fields are rendered - isEdit: false', () => { - const wrapper = mount( - - ); - act(() => { - onChoicesSuccess(mockChoices); - }); - - expect(wrapper.find('[data-test-subj="card-list-item"]').at(0).text()).toEqual( - 'Urgency: 2 - High' - ); - expect(wrapper.find('[data-test-subj="card-list-item"]').at(1).text()).toEqual( - 'Severity: 1 - Critical' - ); - expect(wrapper.find('[data-test-subj="card-list-item"]').at(2).text()).toEqual( - 'Impact: 3 - Moderate' - ); - }); - - test('it transforms the categories to options correctly', async () => { - const wrapper = mount(); - act(() => { - onChoicesSuccess(mockChoices); - }); - - wrapper.update(); - expect(wrapper.find('[data-test-subj="categorySelect"]').first().prop('options')).toEqual([ - { value: 'Priviledge Escalation', text: 'Priviledge Escalation' }, - { - value: 'Criminal activity/investigation', - text: 'Criminal activity/investigation', - }, - { value: 'Denial of Service', text: 'Denial of Service' }, - { - value: 'software', - text: 'Software', - }, - ]); - }); - - test('it transforms the subcategories to options correctly', async () => { - const wrapper = mount(); - act(() => { - onChoicesSuccess(mockChoices); - }); - - wrapper.update(); - expect(wrapper.find('[data-test-subj="subcategorySelect"]').first().prop('options')).toEqual([ - { - text: 'Operation System', - value: 'os', - }, - ]); - }); - - it('it transforms the options correctly', async () => { - const wrapper = mount(); - act(() => { - onChoicesSuccess(mockChoices); - }); - - wrapper.update(); - const testers = ['severity', 'urgency', 'impact']; - testers.forEach((subj) => - expect(wrapper.find(`[data-test-subj="${subj}Select"]`).first().prop('options')).toEqual([ - { value: '1', text: '1 - Critical' }, - { value: '2', text: '2 - High' }, - { value: '3', text: '3 - Moderate' }, - { value: '4', text: '4 - Low' }, - ]) - ); - }); - - describe('onChange calls', () => { - const wrapper = mount(); - - expect(onChange).toHaveBeenCalledWith(fields); - - const testers = ['severity', 'urgency', 'impact', 'subcategory']; - testers.forEach((subj) => - test(`${subj.toUpperCase()}`, async () => { - await waitFor(() => { - const select = wrapper.find(EuiSelect).filter(`[data-test-subj="${subj}Select"]`)!; - select.prop('onChange')!({ - target: { - value: '9', - }, - } as React.ChangeEvent); - }); - wrapper.update(); - expect(onChange).toHaveBeenCalledWith({ - ...fields, - [subj]: '9', - }); - }) - ); - - test('it should set subcategory to null when changing category', async () => { - await waitFor(() => { - const select = wrapper.find(EuiSelect).filter(`[data-test-subj="categorySelect"]`)!; - select.prop('onChange')!({ - target: { - value: 'network', - }, - } as React.ChangeEvent); - }); - wrapper.update(); - expect(onChange).toHaveBeenCalledWith({ - ...fields, - subcategory: null, - category: 'network', - }); - }); - }); -}); diff --git a/x-pack/plugins/cases/public/components/connectors/servicenow/servicenow_itsm_case_fields.tsx b/x-pack/plugins/cases/public/components/connectors/servicenow/servicenow_itsm_case_fields.tsx deleted file mode 100644 index 710e23095835..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/servicenow/servicenow_itsm_case_fields.tsx +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { useCallback, useEffect, useMemo, useState, useRef } from 'react'; -import { EuiFormRow, EuiSelect, EuiSpacer, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import * as i18n from './translations'; - -import { ConnectorFieldsProps } from '../types'; -import { ConnectorTypes, ServiceNowITSMFieldsType } from '../../../../common'; -import { useKibana } from '../../../common/lib/kibana'; -import { ConnectorCard } from '../card'; -import { useGetChoices } from './use_get_choices'; -import { Fields, Choice } from './types'; -import { choicesToEuiOptions } from './helpers'; - -const useGetChoicesFields = ['urgency', 'severity', 'impact', 'category', 'subcategory']; -const defaultFields: Fields = { - urgency: [], - severity: [], - impact: [], - category: [], - subcategory: [], -}; - -const ServiceNowITSMFieldsComponent: React.FunctionComponent< - ConnectorFieldsProps -> = ({ isEdit = true, fields, connector, onChange }) => { - const init = useRef(true); - const { severity = null, urgency = null, impact = null, category = null, subcategory = null } = - fields ?? {}; - const { http, notifications } = useKibana().services; - const [choices, setChoices] = useState(defaultFields); - - const categoryOptions = useMemo(() => choicesToEuiOptions(choices.category), [choices.category]); - const urgencyOptions = useMemo(() => choicesToEuiOptions(choices.urgency), [choices.urgency]); - const severityOptions = useMemo(() => choicesToEuiOptions(choices.severity), [choices.severity]); - const impactOptions = useMemo(() => choicesToEuiOptions(choices.impact), [choices.impact]); - - const subcategoryOptions = useMemo( - () => - choicesToEuiOptions( - choices.subcategory.filter((choice) => choice.dependent_value === category) - ), - [choices.subcategory, category] - ); - - const listItems = useMemo( - () => [ - ...(urgency != null && urgency.length > 0 - ? [ - { - title: i18n.URGENCY, - description: urgencyOptions.find((option) => `${option.value}` === urgency)?.text, - }, - ] - : []), - ...(severity != null && severity.length > 0 - ? [ - { - title: i18n.SEVERITY, - description: severityOptions.find((option) => `${option.value}` === severity)?.text, - }, - ] - : []), - ...(impact != null && impact.length > 0 - ? [ - { - title: i18n.IMPACT, - description: impactOptions.find((option) => `${option.value}` === impact)?.text, - }, - ] - : []), - ...(category != null && category.length > 0 - ? [ - { - title: i18n.CATEGORY, - description: categoryOptions.find((option) => `${option.value}` === category)?.text, - }, - ] - : []), - ...(subcategory != null && subcategory.length > 0 - ? [ - { - title: i18n.SUBCATEGORY, - description: subcategoryOptions.find((option) => `${option.value}` === subcategory) - ?.text, - }, - ] - : []), - ], - [ - category, - categoryOptions, - impact, - impactOptions, - severity, - severityOptions, - subcategory, - subcategoryOptions, - urgency, - urgencyOptions, - ] - ); - - const onChoicesSuccess = (values: Choice[]) => { - setChoices( - values.reduce( - (acc, value) => ({ - ...acc, - [value.element]: [...(acc[value.element] != null ? acc[value.element] : []), value], - }), - defaultFields - ) - ); - }; - - const { isLoading: isLoadingChoices } = useGetChoices({ - http, - toastNotifications: notifications.toasts, - connector, - fields: useGetChoicesFields, - onSuccess: onChoicesSuccess, - }); - - const onChangeCb = useCallback( - ( - key: keyof ServiceNowITSMFieldsType, - value: ServiceNowITSMFieldsType[keyof ServiceNowITSMFieldsType] - ) => { - onChange({ ...fields, [key]: value }); - }, - [fields, onChange] - ); - - // Set field at initialization - useEffect(() => { - if (init.current) { - init.current = false; - onChange({ urgency, severity, impact, category, subcategory }); - } - }, [category, impact, onChange, severity, subcategory, urgency]); - - return isEdit ? ( -
- - onChangeCb('urgency', e.target.value)} - /> - - - - - - onChangeCb('severity', e.target.value)} - /> - - - - - onChangeCb('impact', e.target.value)} - /> - - - - - - - onChange({ ...fields, category: e.target.value, subcategory: null })} - /> - - - - - onChangeCb('subcategory', e.target.value)} - /> - - - -
- ) : ( - - ); -}; - -// eslint-disable-next-line import/no-default-export -export { ServiceNowITSMFieldsComponent as default }; diff --git a/x-pack/plugins/cases/public/components/connectors/servicenow/servicenow_sir_case_fields.test.tsx b/x-pack/plugins/cases/public/components/connectors/servicenow/servicenow_sir_case_fields.test.tsx deleted file mode 100644 index 4a5b34cd3c3c..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/servicenow/servicenow_sir_case_fields.test.tsx +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { mount } from 'enzyme'; -import { waitFor, act } from '@testing-library/react'; -import { EuiSelect } from '@elastic/eui'; - -import { connector, choices as mockChoices } from '../mock'; -import { Choice } from './types'; -import Fields from './servicenow_sir_case_fields'; - -let onChoicesSuccess = (c: Choice[]) => {}; - -jest.mock('../../../common/lib/kibana'); -jest.mock('./use_get_choices', () => ({ - useGetChoices: (args: { onSuccess: () => void }) => { - onChoicesSuccess = args.onSuccess; - return { isLoading: false, mockChoices }; - }, -})); - -describe('ServiceNowSIR Fields', () => { - const fields = { - destIp: true, - sourceIp: true, - malwareHash: true, - malwareUrl: true, - priority: '1', - category: 'Denial of Service', - subcategory: '26', - }; - const onChange = jest.fn(); - - beforeEach(() => { - jest.clearAllMocks(); - }); - - it('all params fields are rendered - isEdit: true', () => { - const wrapper = mount(); - expect(wrapper.find('[data-test-subj="destIpCheckbox"]').exists()).toBeTruthy(); - expect(wrapper.find('[data-test-subj="sourceIpCheckbox"]').exists()).toBeTruthy(); - expect(wrapper.find('[data-test-subj="malwareUrlCheckbox"]').exists()).toBeTruthy(); - expect(wrapper.find('[data-test-subj="malwareHashCheckbox"]').exists()).toBeTruthy(); - expect(wrapper.find('[data-test-subj="prioritySelect"]').exists()).toBeTruthy(); - expect(wrapper.find('[data-test-subj="categorySelect"]').exists()).toBeTruthy(); - expect(wrapper.find('[data-test-subj="subcategorySelect"]').exists()).toBeTruthy(); - }); - - test('all params fields are rendered - isEdit: false', () => { - const wrapper = mount( - - ); - act(() => { - onChoicesSuccess(mockChoices); - }); - wrapper.update(); - - expect(wrapper.find('[data-test-subj="card-list-item"]').at(0).text()).toEqual( - 'Destination IP: Yes' - ); - expect(wrapper.find('[data-test-subj="card-list-item"]').at(1).text()).toEqual( - 'Source IP: Yes' - ); - expect(wrapper.find('[data-test-subj="card-list-item"]').at(2).text()).toEqual( - 'Malware URL: Yes' - ); - expect(wrapper.find('[data-test-subj="card-list-item"]').at(3).text()).toEqual( - 'Malware Hash: Yes' - ); - expect(wrapper.find('[data-test-subj="card-list-item"]').at(4).text()).toEqual( - 'Priority: 1 - Critical' - ); - expect(wrapper.find('[data-test-subj="card-list-item"]').at(5).text()).toEqual( - 'Category: Denial of Service' - ); - expect(wrapper.find('[data-test-subj="card-list-item"]').at(6).text()).toEqual( - 'Subcategory: Single or distributed (DoS or DDoS)' - ); - }); - - test('it transforms the categories to options correctly', async () => { - const wrapper = mount(); - act(() => { - onChoicesSuccess(mockChoices); - }); - - wrapper.update(); - expect(wrapper.find('[data-test-subj="categorySelect"]').first().prop('options')).toEqual([ - { value: 'Priviledge Escalation', text: 'Priviledge Escalation' }, - { - value: 'Criminal activity/investigation', - text: 'Criminal activity/investigation', - }, - { value: 'Denial of Service', text: 'Denial of Service' }, - { - text: 'Software', - value: 'software', - }, - ]); - }); - - test('it transforms the subcategories to options correctly', async () => { - const wrapper = mount(); - act(() => { - onChoicesSuccess(mockChoices); - }); - - wrapper.update(); - expect(wrapper.find('[data-test-subj="subcategorySelect"]').first().prop('options')).toEqual([ - { - text: 'Inbound or outbound', - value: '12', - }, - { - text: 'Single or distributed (DoS or DDoS)', - value: '26', - }, - { - text: 'Inbound DDos', - value: 'inbound_ddos', - }, - ]); - }); - - test('it transforms the priorities to options correctly', async () => { - const wrapper = mount(); - act(() => { - onChoicesSuccess(mockChoices); - }); - - wrapper.update(); - expect(wrapper.find('[data-test-subj="prioritySelect"]').first().prop('options')).toEqual([ - { - text: '1 - Critical', - value: '1', - }, - { - text: '2 - High', - value: '2', - }, - { - text: '3 - Moderate', - value: '3', - }, - { - text: '4 - Low', - value: '4', - }, - ]); - }); - - describe('onChange calls', () => { - const wrapper = mount(); - - act(() => { - onChoicesSuccess(mockChoices); - }); - wrapper.update(); - - expect(onChange).toHaveBeenCalledWith(fields); - - const checkbox = ['destIp', 'sourceIp', 'malwareHash', 'malwareUrl']; - checkbox.forEach((subj) => - test(`${subj.toUpperCase()}`, async () => { - await waitFor(() => { - wrapper - .find(`[data-test-subj="${subj}Checkbox"] input`) - .first() - .simulate('change', { target: { checked: false } }); - expect(onChange).toHaveBeenCalledWith({ - ...fields, - [subj]: false, - }); - }); - }) - ); - - const testers = ['priority', 'subcategory']; - testers.forEach((subj) => - test(`${subj.toUpperCase()}`, async () => { - await waitFor(() => { - const select = wrapper.find(EuiSelect).filter(`[data-test-subj="${subj}Select"]`)!; - select.prop('onChange')!({ - target: { - value: '9', - }, - } as React.ChangeEvent); - }); - wrapper.update(); - expect(onChange).toHaveBeenCalledWith({ - ...fields, - [subj]: '9', - }); - }) - ); - - test('it should set subcategory to null when changing category', async () => { - const select = wrapper.find(EuiSelect).filter(`[data-test-subj="categorySelect"]`)!; - select.prop('onChange')!({ - target: { - value: 'network', - }, - } as React.ChangeEvent); - - wrapper.update(); - - await waitFor(() => { - expect(onChange).toHaveBeenCalledWith({ - ...fields, - subcategory: null, - category: 'network', - }); - }); - }); - }); -}); diff --git a/x-pack/plugins/cases/public/components/connectors/servicenow/servicenow_sir_case_fields.tsx b/x-pack/plugins/cases/public/components/connectors/servicenow/servicenow_sir_case_fields.tsx deleted file mode 100644 index 1f9a7cf7acd6..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/servicenow/servicenow_sir_case_fields.tsx +++ /dev/null @@ -1,282 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { useCallback, useEffect, useMemo, useState, useRef } from 'react'; -import { EuiFormRow, EuiSelect, EuiFlexGroup, EuiFlexItem, EuiCheckbox } from '@elastic/eui'; - -import { ConnectorTypes, ServiceNowSIRFieldsType } from '../../../../common'; -import { useKibana } from '../../../common/lib/kibana'; -import { ConnectorFieldsProps } from '../types'; -import { ConnectorCard } from '../card'; -import { useGetChoices } from './use_get_choices'; -import { Choice, Fields } from './types'; -import { choicesToEuiOptions } from './helpers'; - -import * as i18n from './translations'; - -const useGetChoicesFields = ['category', 'subcategory', 'priority']; -const defaultFields: Fields = { - category: [], - subcategory: [], - priority: [], -}; - -const ServiceNowSIRFieldsComponent: React.FunctionComponent< - ConnectorFieldsProps -> = ({ isEdit = true, fields, connector, onChange }) => { - const init = useRef(true); - const { - category = null, - destIp = true, - malwareHash = true, - malwareUrl = true, - priority = null, - sourceIp = true, - subcategory = null, - } = fields ?? {}; - - const { http, notifications } = useKibana().services; - - const [choices, setChoices] = useState(defaultFields); - - const onChangeCb = useCallback( - ( - key: keyof ServiceNowSIRFieldsType, - value: ServiceNowSIRFieldsType[keyof ServiceNowSIRFieldsType] - ) => { - onChange({ ...fields, [key]: value }); - }, - [fields, onChange] - ); - - const onChoicesSuccess = (values: Choice[]) => { - setChoices( - values.reduce( - (acc, value) => ({ - ...acc, - [value.element]: [...(acc[value.element] != null ? acc[value.element] : []), value], - }), - defaultFields - ) - ); - }; - - const { isLoading: isLoadingChoices } = useGetChoices({ - http, - toastNotifications: notifications.toasts, - connector, - fields: useGetChoicesFields, - onSuccess: onChoicesSuccess, - }); - - const categoryOptions = useMemo(() => choicesToEuiOptions(choices.category), [choices.category]); - const priorityOptions = useMemo(() => choicesToEuiOptions(choices.priority), [choices.priority]); - - const subcategoryOptions = useMemo( - () => - choicesToEuiOptions( - choices.subcategory.filter((choice) => choice.dependent_value === category) - ), - [choices.subcategory, category] - ); - - const listItems = useMemo( - () => [ - ...(destIp != null && destIp - ? [ - { - title: i18n.DEST_IP, - description: i18n.ALERT_FIELD_ENABLED_TEXT, - }, - ] - : []), - ...(sourceIp != null && sourceIp - ? [ - { - title: i18n.SOURCE_IP, - description: i18n.ALERT_FIELD_ENABLED_TEXT, - }, - ] - : []), - ...(malwareUrl != null && malwareUrl - ? [ - { - title: i18n.MALWARE_URL, - description: i18n.ALERT_FIELD_ENABLED_TEXT, - }, - ] - : []), - ...(malwareHash != null && malwareHash - ? [ - { - title: i18n.MALWARE_HASH, - description: i18n.ALERT_FIELD_ENABLED_TEXT, - }, - ] - : []), - ...(priority != null && priority.length > 0 - ? [ - { - title: i18n.PRIORITY, - description: priorityOptions.find((option) => `${option.value}` === priority)?.text, - }, - ] - : []), - ...(category != null && category.length > 0 - ? [ - { - title: i18n.CATEGORY, - description: categoryOptions.find((option) => `${option.value}` === category)?.text, - }, - ] - : []), - ...(subcategory != null && subcategory.length > 0 - ? [ - { - title: i18n.SUBCATEGORY, - description: subcategoryOptions.find((option) => `${option.value}` === subcategory) - ?.text, - }, - ] - : []), - ], - [ - category, - categoryOptions, - destIp, - malwareHash, - malwareUrl, - priority, - priorityOptions, - sourceIp, - subcategory, - subcategoryOptions, - ] - ); - - // Set field at initialization - useEffect(() => { - if (init.current) { - init.current = false; - onChange({ category, destIp, malwareHash, malwareUrl, priority, sourceIp, subcategory }); - } - }, [category, destIp, malwareHash, malwareUrl, onChange, priority, sourceIp, subcategory]); - - return isEdit ? ( -
- - - - <> - - - onChangeCb('destIp', e.target.checked)} - /> - - - onChangeCb('sourceIp', e.target.checked)} - /> - - - - - onChangeCb('malwareUrl', e.target.checked)} - /> - - - onChangeCb('malwareHash', e.target.checked)} - /> - - - - - - - - - - onChangeCb('priority', e.target.value)} - /> - - - - - - - onChange({ ...fields, category: e.target.value, subcategory: null })} - /> - - - - - onChangeCb('subcategory', e.target.value)} - /> - - - -
- ) : ( - - ); -}; - -// eslint-disable-next-line import/no-default-export -export { ServiceNowSIRFieldsComponent as default }; diff --git a/x-pack/plugins/cases/public/components/connectors/servicenow/translations.ts b/x-pack/plugins/cases/public/components/connectors/servicenow/translations.ts deleted file mode 100644 index fc48ecf17f2c..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/servicenow/translations.ts +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; - -export const URGENCY = i18n.translate('xpack.cases.connectors.serviceNow.urgencySelectFieldLabel', { - defaultMessage: 'Urgency', -}); - -export const SEVERITY = i18n.translate( - 'xpack.cases.connectors.serviceNow.severitySelectFieldLabel', - { - defaultMessage: 'Severity', - } -); - -export const IMPACT = i18n.translate('xpack.cases.connectors.serviceNow.impactSelectFieldLabel', { - defaultMessage: 'Impact', -}); - -export const CHOICES_API_ERROR = i18n.translate( - 'xpack.cases.connectors.serviceNow.unableToGetChoicesMessage', - { - defaultMessage: 'Unable to get choices', - } -); - -export const MALWARE_URL = i18n.translate('xpack.cases.connectors.serviceNow.malwareURLTitle', { - defaultMessage: 'Malware URL', -}); - -export const MALWARE_HASH = i18n.translate('xpack.cases.connectors.serviceNow.malwareHashTitle', { - defaultMessage: 'Malware Hash', -}); - -export const CATEGORY = i18n.translate('xpack.cases.connectors.serviceNow.categoryTitle', { - defaultMessage: 'Category', -}); - -export const SUBCATEGORY = i18n.translate('xpack.cases.connectors.serviceNow.subcategoryTitle', { - defaultMessage: 'Subcategory', -}); - -export const SOURCE_IP = i18n.translate('xpack.cases.connectors.serviceNow.sourceIPTitle', { - defaultMessage: 'Source IP', -}); - -export const DEST_IP = i18n.translate('xpack.cases.connectors.serviceNow.destinationIPTitle', { - defaultMessage: 'Destination IP', -}); - -export const PRIORITY = i18n.translate( - 'xpack.cases.connectors.serviceNow.prioritySelectFieldTitle', - { - defaultMessage: 'Priority', - } -); - -export const ALERT_FIELDS_LABEL = i18n.translate( - 'xpack.cases.connectors.serviceNow.alertFieldsTitle', - { - defaultMessage: 'Select Observables to push', - } -); - -export const ALERT_FIELD_ENABLED_TEXT = i18n.translate( - 'xpack.cases.connectors.serviceNow.alertFieldEnabledText', - { - defaultMessage: 'Yes', - } -); diff --git a/x-pack/plugins/cases/public/components/connectors/servicenow/types.ts b/x-pack/plugins/cases/public/components/connectors/servicenow/types.ts deleted file mode 100644 index fd1af62f7bb2..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/servicenow/types.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export interface Choice { - value: string; - label: string; - dependent_value: string; - element: string; -} - -export type Fields = Record; diff --git a/x-pack/plugins/cases/public/components/connectors/servicenow/use_get_choices.test.tsx b/x-pack/plugins/cases/public/components/connectors/servicenow/use_get_choices.test.tsx deleted file mode 100644 index ed4577dd0114..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/servicenow/use_get_choices.test.tsx +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { renderHook } from '@testing-library/react-hooks'; - -import { useKibana } from '../../../common/lib/kibana'; -import { ActionConnector } from '../../../containers/types'; -import { choices } from '../mock'; -import { useGetChoices, UseGetChoices, UseGetChoicesProps } from './use_get_choices'; -import * as api from './api'; - -jest.mock('./api'); -jest.mock('../../../common/lib/kibana'); - -const useKibanaMock = useKibana as jest.Mocked; -const onSuccess = jest.fn(); -const fields = ['priority']; - -const connector = { - secrets: { - username: 'user', - password: 'pass', - }, - id: 'test', - actionTypeId: '.servicenow', - name: 'ServiceNow', - isPreconfigured: false, - config: { - apiUrl: 'https://dev94428.service-now.com/', - }, -} as ActionConnector; - -describe('useGetChoices', () => { - const { services } = useKibanaMock(); - beforeEach(() => { - jest.clearAllMocks(); - }); - - it('init', async () => { - const { result, waitForNextUpdate } = renderHook(() => - useGetChoices({ - http: services.http, - connector, - toastNotifications: services.notifications.toasts, - fields, - onSuccess, - }) - ); - - await waitForNextUpdate(); - - expect(result.current).toEqual({ - isLoading: false, - choices, - }); - }); - - it('returns an empty array when connector is not presented', async () => { - const { result } = renderHook(() => - useGetChoices({ - http: services.http, - connector: undefined, - toastNotifications: services.notifications.toasts, - fields, - onSuccess, - }) - ); - - expect(result.current).toEqual({ - isLoading: false, - choices: [], - }); - }); - - it('it calls onSuccess', async () => { - const { waitForNextUpdate } = renderHook(() => - useGetChoices({ - http: services.http, - connector, - toastNotifications: services.notifications.toasts, - fields, - onSuccess, - }) - ); - - await waitForNextUpdate(); - - expect(onSuccess).toHaveBeenCalledWith(choices); - }); - - it('it displays an error when service fails', async () => { - const spyOnGetChoices = jest.spyOn(api, 'getChoices'); - spyOnGetChoices.mockResolvedValue( - Promise.resolve({ - actionId: 'test', - status: 'error', - serviceMessage: 'An error occurred', - }) - ); - - const { waitForNextUpdate } = renderHook(() => - useGetChoices({ - http: services.http, - connector, - toastNotifications: services.notifications.toasts, - fields, - onSuccess, - }) - ); - - await waitForNextUpdate(); - - expect(services.notifications.toasts.addDanger).toHaveBeenCalledWith({ - text: 'An error occurred', - title: 'Unable to get choices', - }); - }); - - it('it displays an error when http throws an error', async () => { - const spyOnGetChoices = jest.spyOn(api, 'getChoices'); - spyOnGetChoices.mockImplementation(() => { - throw new Error('An error occurred'); - }); - - renderHook(() => - useGetChoices({ - http: services.http, - connector, - toastNotifications: services.notifications.toasts, - fields, - onSuccess, - }) - ); - - expect(services.notifications.toasts.addDanger).toHaveBeenCalledWith({ - text: 'An error occurred', - title: 'Unable to get choices', - }); - }); -}); diff --git a/x-pack/plugins/cases/public/components/connectors/servicenow/use_get_choices.tsx b/x-pack/plugins/cases/public/components/connectors/servicenow/use_get_choices.tsx deleted file mode 100644 index a979f96d84ab..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/servicenow/use_get_choices.tsx +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { useState, useEffect, useRef } from 'react'; -import { HttpSetup, ToastsApi } from 'kibana/public'; -import { ActionConnector } from '../../../containers/types'; -import { getChoices } from './api'; -import { Choice } from './types'; -import * as i18n from './translations'; - -export interface UseGetChoicesProps { - http: HttpSetup; - toastNotifications: Pick< - ToastsApi, - 'get$' | 'add' | 'remove' | 'addSuccess' | 'addWarning' | 'addDanger' | 'addError' - >; - connector?: ActionConnector; - fields: string[]; - onSuccess?: (choices: Choice[]) => void; -} - -export interface UseGetChoices { - choices: Choice[]; - isLoading: boolean; -} - -export const useGetChoices = ({ - http, - connector, - toastNotifications, - fields, - onSuccess, -}: UseGetChoicesProps): UseGetChoices => { - const [isLoading, setIsLoading] = useState(false); - const [choices, setChoices] = useState([]); - const didCancel = useRef(false); - const abortCtrl = useRef(new AbortController()); - - useEffect(() => { - const fetchData = async () => { - if (!connector) { - setIsLoading(false); - return; - } - - try { - abortCtrl.current = new AbortController(); - setIsLoading(true); - - const res = await getChoices({ - http, - signal: abortCtrl.current.signal, - connectorId: connector.id, - fields, - }); - - if (!didCancel.current) { - setIsLoading(false); - setChoices(res.data ?? []); - if (res.status && res.status === 'error') { - toastNotifications.addDanger({ - title: i18n.CHOICES_API_ERROR, - text: `${res.serviceMessage ?? res.message}`, - }); - } else if (onSuccess) { - onSuccess(res.data ?? []); - } - } - } catch (error) { - if (!didCancel.current) { - setIsLoading(false); - if (error.name !== 'AbortError') { - toastNotifications.addDanger({ - title: i18n.CHOICES_API_ERROR, - text: error.message, - }); - } - } - } - }; - - didCancel.current = false; - abortCtrl.current.abort(); - fetchData(); - - return () => { - didCancel.current = true; - abortCtrl.current.abort(); - }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [http, connector, toastNotifications, fields]); - - return { - choices, - isLoading, - }; -}; diff --git a/x-pack/plugins/cases/public/components/connectors/types.ts b/x-pack/plugins/cases/public/components/connectors/types.ts deleted file mode 100644 index fc2f66d33170..000000000000 --- a/x-pack/plugins/cases/public/components/connectors/types.ts +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { - ActionType as ThirdPartySupportedActions, - CaseField, - ActionConnector, - ConnectorTypeFields, -} from '../../../common'; - -export { ThirdPartyField as AllThirdPartyFields } from '../../../common'; -export type CaseActionConnector = ActionConnector; - -export interface ThirdPartyField { - label: string; - validSourceFields: CaseField[]; - defaultSourceField: CaseField; - defaultActionType: ThirdPartySupportedActions; -} - -export interface ConnectorConfiguration { - name: string; - logo: string; -} - -export interface CaseConnector { - id: string; - fieldsComponent: React.LazyExoticComponent< - React.ComponentType> - > | null; -} - -export interface CaseConnectorsRegistry { - has: (id: string) => boolean; - register: ( - connector: CaseConnector - ) => void; - get: (id: string) => CaseConnector; - list: () => CaseConnector[]; -} - -export interface ConnectorFieldsProps { - isEdit?: boolean; - connector: CaseActionConnector; - fields: TFields; - onChange: (fields: TFields) => void; -} diff --git a/x-pack/plugins/cases/public/components/create/connector.test.tsx b/x-pack/plugins/cases/public/components/create/connector.test.tsx deleted file mode 100644 index db9e5ffac153..000000000000 --- a/x-pack/plugins/cases/public/components/create/connector.test.tsx +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { mount } from 'enzyme'; -import { act, waitFor } from '@testing-library/react'; -import { EuiComboBox, EuiComboBoxOptionOption } from '@elastic/eui'; - -import { useForm, Form, FormHook } from '../../common/shared_imports'; -import { connectorsMock } from '../../containers/mock'; -import { Connector } from './connector'; -import { useConnectors } from '../../containers/configure/use_connectors'; -import { useGetIncidentTypes } from '../connectors/resilient/use_get_incident_types'; -import { useGetSeverity } from '../connectors/resilient/use_get_severity'; -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: {}, - }, - }), - }; -}); -jest.mock('../../containers/configure/use_connectors'); -jest.mock('../connectors/resilient/use_get_incident_types'); -jest.mock('../connectors/resilient/use_get_severity'); -jest.mock('../connectors/servicenow/use_get_choices'); - -const useConnectorsMock = useConnectors as jest.Mock; -const useGetIncidentTypesMock = useGetIncidentTypes as jest.Mock; -const useGetSeverityMock = useGetSeverity as jest.Mock; -const useGetChoicesMock = useGetChoices as jest.Mock; - -const useGetIncidentTypesResponse = { - isLoading: false, - incidentTypes, -}; - -const useGetSeverityResponse = { - isLoading: false, - severity, -}; - -const useGetChoicesResponse = { - isLoading: false, - choices, -}; - -describe('Connector', () => { - let globalForm: FormHook; - - const MockHookWrapperComponent: React.FC = ({ children }) => { - const { form } = useForm({ - defaultValue: { connectorId: connectorsMock[0].id, fields: null }, - schema: { - connectorId: schema.connectorId, - fields: schema.fields, - }, - }); - - globalForm = form; - - return
{children}
; - }; - - beforeEach(() => { - jest.resetAllMocks(); - useConnectorsMock.mockReturnValue({ loading: false, connectors: connectorsMock }); - useGetIncidentTypesMock.mockReturnValue(useGetIncidentTypesResponse); - useGetSeverityMock.mockReturnValue(useGetSeverityResponse); - useGetChoicesMock.mockReturnValue(useGetChoicesResponse); - }); - - it('it renders', async () => { - const wrapper = mount( - - - - ); - - expect(wrapper.find(`[data-test-subj="caseConnectors"]`).exists()).toBeTruthy(); - expect(wrapper.find(`[data-test-subj="connector-fields"]`).exists()).toBeTruthy(); - - await waitFor(() => { - expect(wrapper.find(`button[data-test-subj="dropdown-connectors"]`).first().text()).toBe( - 'My Connector' - ); - }); - - await waitFor(() => { - wrapper.update(); - expect(wrapper.find(`[data-test-subj="connector-fields-sn-itsm"]`).exists()).toBeTruthy(); - }); - }); - - it('it is loading when fetching connectors', async () => { - useConnectorsMock.mockReturnValue({ loading: true, connectors: connectorsMock }); - const wrapper = mount( - - - - ); - - expect( - wrapper.find('[data-test-subj="dropdown-connectors"]').first().prop('isLoading') - ).toEqual(true); - }); - - it('it is disabled when fetching connectors', async () => { - useConnectorsMock.mockReturnValue({ loading: true, connectors: connectorsMock }); - const wrapper = mount( - - - - ); - - expect(wrapper.find('[data-test-subj="dropdown-connectors"]').first().prop('disabled')).toEqual( - true - ); - }); - - it('it is disabled and loading when passing loading as true', async () => { - const wrapper = mount( - - - - ); - - expect( - wrapper.find('[data-test-subj="dropdown-connectors"]').first().prop('isLoading') - ).toEqual(true); - expect(wrapper.find('[data-test-subj="dropdown-connectors"]').first().prop('disabled')).toEqual( - true - ); - }); - - it(`it should change connector`, async () => { - const wrapper = mount( - - - - ); - - await waitFor(() => { - expect(wrapper.find(`[data-test-subj="connector-fields-resilient"]`).exists()).toBeFalsy(); - wrapper.find('button[data-test-subj="dropdown-connectors"]').simulate('click'); - wrapper.find(`button[data-test-subj="dropdown-connector-resilient-2"]`).simulate('click'); - wrapper.update(); - }); - - await waitFor(() => { - wrapper.update(); - expect(wrapper.find(`[data-test-subj="connector-fields-resilient"]`).exists()).toBeTruthy(); - }); - - act(() => { - ((wrapper.find(EuiComboBox).props() as unknown) as { - onChange: (a: EuiComboBoxOptionOption[]) => void; - }).onChange([{ value: '19', label: 'Denial of Service' }]); - }); - - act(() => { - wrapper - .find('select[data-test-subj="severitySelect"]') - .first() - .simulate('change', { - target: { value: '4' }, - }); - }); - - await waitFor(() => { - expect(globalForm.getFormData()).toEqual({ - connectorId: 'resilient-2', - fields: { incidentTypes: ['19'], severityCode: '4' }, - }); - }); - }); -}); diff --git a/x-pack/plugins/cases/public/components/create/connector.tsx b/x-pack/plugins/cases/public/components/create/connector.tsx deleted file mode 100644 index 9b6063a7bf9b..000000000000 --- a/x-pack/plugins/cases/public/components/create/connector.tsx +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { memo, useCallback } from 'react'; -import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; - -import { ConnectorTypes } from '../../../common'; -import { UseField, useFormData, FieldHook, useFormContext } from '../../common/shared_imports'; -import { useConnectors } from '../../containers/configure/use_connectors'; -import { ConnectorSelector } from '../connector_selector/form'; -import { ConnectorFieldsForm } from '../connectors/fields_form'; -import { ActionConnector } from '../../containers/types'; -import { getConnectorById } from '../configure_cases/utils'; -import { FormProps } from './schema'; - -interface Props { - isLoading: boolean; - hideConnectorServiceNowSir?: boolean; -} - -interface ConnectorsFieldProps { - connectors: ActionConnector[]; - field: FieldHook; - isEdit: boolean; - hideConnectorServiceNowSir?: boolean; -} - -const ConnectorFields = ({ - connectors, - isEdit, - field, - hideConnectorServiceNowSir = false, -}: ConnectorsFieldProps) => { - const [{ connectorId }] = useFormData({ watch: ['connectorId'] }); - const { setValue } = field; - let connector = getConnectorById(connectorId, connectors) ?? null; - if ( - connector && - hideConnectorServiceNowSir && - connector.actionTypeId === ConnectorTypes.serviceNowSIR - ) { - connector = null; - } - return ( - - ); -}; - -const ConnectorComponent: React.FC = ({ hideConnectorServiceNowSir = false, isLoading }) => { - const { getFields } = useFormContext(); - const { loading: isLoadingConnectors, connectors } = useConnectors(); - const handleConnectorChange = useCallback( - (newConnector) => { - const { fields } = getFields(); - fields.setValue(null); - }, - [getFields] - ); - - return ( - - - - - - - - - ); -}; - -ConnectorComponent.displayName = 'ConnectorComponent'; - -export const Connector = memo(ConnectorComponent); diff --git a/x-pack/plugins/cases/public/components/create/description.test.tsx b/x-pack/plugins/cases/public/components/create/description.test.tsx deleted file mode 100644 index fcd1f82d64a5..000000000000 --- a/x-pack/plugins/cases/public/components/create/description.test.tsx +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { mount } from 'enzyme'; -import { act } from '@testing-library/react'; - -import { useForm, Form, FormHook } from '../../common/shared_imports'; -import { Description } from './description'; -import { schema, FormProps } from './schema'; - -describe('Description', () => { - let globalForm: FormHook; - - const MockHookWrapperComponent: React.FC = ({ children }) => { - const { form } = useForm({ - defaultValue: { description: 'My description' }, - schema: { - description: schema.description, - }, - }); - - globalForm = form; - - return
{children}
; - }; - - beforeEach(() => { - jest.resetAllMocks(); - }); - - it('it renders', async () => { - const wrapper = mount( - - - - ); - - expect(wrapper.find(`[data-test-subj="caseDescription"]`).exists()).toBeTruthy(); - }); - - it('it changes the description', async () => { - const wrapper = mount( - - - - ); - - await act(async () => { - wrapper - .find(`[data-test-subj="caseDescription"] textarea`) - .first() - .simulate('change', { target: { value: 'My new description' } }); - }); - - expect(globalForm.getFormData()).toEqual({ description: 'My new description' }); - }); -}); diff --git a/x-pack/plugins/cases/public/components/create/description.tsx b/x-pack/plugins/cases/public/components/create/description.tsx deleted file mode 100644 index 0a7102cff1ad..000000000000 --- a/x-pack/plugins/cases/public/components/create/description.tsx +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { memo } from 'react'; -import { MarkdownEditorForm } from '../markdown_editor'; -import { UseField } from '../../common/shared_imports'; -interface Props { - isLoading: boolean; -} - -export const fieldName = 'description'; - -const DescriptionComponent: React.FC = ({ isLoading }) => ( - -); - -DescriptionComponent.displayName = 'DescriptionComponent'; - -export const Description = memo(DescriptionComponent); diff --git a/x-pack/plugins/cases/public/components/create/flyout.test.tsx b/x-pack/plugins/cases/public/components/create/flyout.test.tsx deleted file mode 100644 index 5187029ab60c..000000000000 --- a/x-pack/plugins/cases/public/components/create/flyout.test.tsx +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { ReactNode } from 'react'; -import { mount } from 'enzyme'; - -import { CreateCaseFlyout } from './flyout'; -import { TestProviders } from '../../common/mock'; - -jest.mock('../create/form_context', () => { - return { - FormContext: ({ - children, - onSuccess, - }: { - children: ReactNode; - onSuccess: ({ id }: { id: string }) => Promise; - }) => { - return ( - <> - - {children} - - ); - }, - }; -}); - -jest.mock('../create/form', () => { - return { - CreateCaseForm: () => { - return <>{'form'}; - }, - }; -}); - -jest.mock('../create/submit_button', () => { - return { - SubmitCaseButton: () => { - return <>{'Submit'}; - }, - }; -}); - -const onCloseFlyout = jest.fn(); -const onSuccess = jest.fn(); -const defaultProps = { - onCloseFlyout, - onSuccess, -}; - -describe('CreateCaseFlyout', () => { - beforeEach(() => { - jest.resetAllMocks(); - }); - - it('renders', () => { - const wrapper = mount( - - - - ); - - expect(wrapper.find(`[data-test-subj='create-case-flyout']`).exists()).toBeTruthy(); - }); - - it('Closing modal calls onCloseCaseModal', () => { - const wrapper = mount( - - - - ); - - wrapper.find('.euiFlyout__closeButton').first().simulate('click'); - expect(onCloseFlyout).toBeCalled(); - }); - - it('pass the correct props to FormContext component', () => { - const wrapper = mount( - - - - ); - - const props = wrapper.find('FormContext').props(); - expect(props).toEqual( - expect.objectContaining({ - onSuccess, - }) - ); - }); - - it('onSuccess called when creating a case', () => { - const wrapper = mount( - - - - ); - - wrapper.find(`[data-test-subj='form-context-on-success']`).first().simulate('click'); - expect(onSuccess).toHaveBeenCalledWith({ id: 'case-id' }); - }); -}); diff --git a/x-pack/plugins/cases/public/components/create/flyout.tsx b/x-pack/plugins/cases/public/components/create/flyout.tsx deleted file mode 100644 index 8ed09865e9ea..000000000000 --- a/x-pack/plugins/cases/public/components/create/flyout.tsx +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { memo } from 'react'; -import styled from 'styled-components'; -import { EuiFlyout, EuiFlyoutHeader, EuiTitle, EuiFlyoutBody } from '@elastic/eui'; - -import { FormContext } from '../create/form_context'; -import { CreateCaseForm } from '../create/form'; -import { SubmitCaseButton } from '../create/submit_button'; -import { Case } from '../../containers/types'; -import * as i18n from '../../common/translations'; - -export interface CreateCaseModalProps { - onCloseFlyout: () => void; - onSuccess: (theCase: Case) => Promise; - afterCaseCreated?: (theCase: Case) => Promise; -} - -const Container = styled.div` - ${({ theme }) => ` - margin-top: ${theme.eui.euiSize}; - text-align: right; - `} -`; - -const StyledFlyout = styled(EuiFlyout)` - ${({ theme }) => ` - z-index: ${theme.eui.euiZModal}; - `} -`; - -// Adding bottom padding because timeline's -// bottom bar gonna hide the submit button. -const FormWrapper = styled.div` - padding-bottom: 50px; -`; - -const CreateCaseFlyoutComponent: React.FC = ({ - onSuccess, - afterCaseCreated, - onCloseFlyout, -}) => { - return ( - - - -

{i18n.CREATE_TITLE}

-
-
- - - - - - - - - - -
- ); -}; - -export const CreateCaseFlyout = memo(CreateCaseFlyoutComponent); - -CreateCaseFlyout.displayName = 'CreateCaseFlyout'; diff --git a/x-pack/plugins/cases/public/components/create/form.test.tsx b/x-pack/plugins/cases/public/components/create/form.test.tsx deleted file mode 100644 index 9e59924bdf48..000000000000 --- a/x-pack/plugins/cases/public/components/create/form.test.tsx +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { mount } from 'enzyme'; -import { act, waitFor } from '@testing-library/react'; - -import { useForm, Form, FormHook } from '../../common/shared_imports'; -import { useGetTags } from '../../containers/use_get_tags'; -import { useConnectors } from '../../containers/configure/use_connectors'; -import { connectorsMock } from '../../containers/mock'; -import { schema, FormProps } from './schema'; -import { CreateCaseForm } from './form'; - -jest.mock('../../containers/use_get_tags'); -jest.mock('../../containers/configure/use_connectors'); -const useGetTagsMock = useGetTags as jest.Mock; -const useConnectorsMock = useConnectors as jest.Mock; - -const initialCaseValue: FormProps = { - description: '', - tags: [], - title: '', - connectorId: 'none', - fields: null, - syncAlerts: true, -}; - -describe('CreateCaseForm', () => { - let globalForm: FormHook; - const MockHookWrapperComponent: React.FC = ({ children }) => { - const { form } = useForm({ - defaultValue: initialCaseValue, - options: { stripEmptyFields: false }, - schema, - }); - - globalForm = form; - - return
{children}
; - }; - - beforeEach(() => { - jest.resetAllMocks(); - useGetTagsMock.mockReturnValue({ tags: ['test'] }); - useConnectorsMock.mockReturnValue({ loading: false, connectors: connectorsMock }); - }); - - it('it renders with steps', async () => { - const wrapper = mount( - - - - ); - - expect(wrapper.find(`[data-test-subj="case-creation-form-steps"]`).exists()).toBeTruthy(); - }); - - it('it renders without steps', async () => { - const wrapper = mount( - - - - ); - - expect(wrapper.find(`[data-test-subj="case-creation-form-steps"]`).exists()).toBeFalsy(); - }); - - it('it renders all form fields', async () => { - const wrapper = mount( - - - - ); - - expect(wrapper.find(`[data-test-subj="caseTitle"]`).exists()).toBeTruthy(); - expect(wrapper.find(`[data-test-subj="caseTags"]`).exists()).toBeTruthy(); - expect(wrapper.find(`[data-test-subj="caseDescription"]`).exists()).toBeTruthy(); - expect(wrapper.find(`[data-test-subj="caseSyncAlerts"]`).exists()).toBeTruthy(); - expect(wrapper.find(`[data-test-subj="caseConnectors"]`).exists()).toBeTruthy(); - }); - - it('should render spinner when loading', async () => { - const wrapper = mount( - - - - ); - - await act(async () => { - globalForm.setFieldValue('title', 'title'); - globalForm.setFieldValue('description', 'description'); - globalForm.submit(); - // For some weird reason this is needed to pass the test. - // It does not do anything useful - await wrapper.find(`[data-test-subj="caseTitle"]`); - await wrapper.update(); - await waitFor(() => { - expect( - wrapper.find(`[data-test-subj="create-case-loading-spinner"]`).exists() - ).toBeTruthy(); - }); - }); - }); -}); diff --git a/x-pack/plugins/cases/public/components/create/form.tsx b/x-pack/plugins/cases/public/components/create/form.tsx deleted file mode 100644 index a81ecf32576a..000000000000 --- a/x-pack/plugins/cases/public/components/create/form.tsx +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { useMemo } from 'react'; -import { EuiLoadingSpinner, EuiSteps } from '@elastic/eui'; -import styled, { css } from 'styled-components'; - -import { useFormContext } from '../../common/shared_imports'; - -import { Title } from './title'; -import { Description } from './description'; -import { Tags } from './tags'; -import { Connector } from './connector'; -import * as i18n from './translations'; -import { SyncAlertsToggle } from './sync_alerts_toggle'; - -interface ContainerProps { - big?: boolean; -} - -const Container = styled.div.attrs((props) => props)` - ${({ big, theme }) => css` - margin-top: ${big ? theme.eui?.euiSizeXL ?? '32px' : theme.eui?.euiSize ?? '16px'}; - `} -`; - -const MySpinner = styled(EuiLoadingSpinner)` - position: absolute; - top: 50%; - left: 50%; - z-index: 99; -`; - -interface Props { - hideConnectorServiceNowSir?: boolean; - withSteps?: boolean; -} - -export const CreateCaseForm: React.FC = React.memo( - ({ hideConnectorServiceNowSir = false, withSteps = true }) => { - const { isSubmitting } = useFormContext(); - - const firstStep = useMemo( - () => ({ - title: i18n.STEP_ONE_TITLE, - children: ( - <> - - <Container> - <Tags isLoading={isSubmitting} /> - </Container> - <Container big> - <Description isLoading={isSubmitting} /> - </Container> - </> - ), - }), - [isSubmitting] - ); - - const secondStep = useMemo( - () => ({ - title: i18n.STEP_TWO_TITLE, - children: ( - <Container> - <SyncAlertsToggle isLoading={isSubmitting} /> - </Container> - ), - }), - [isSubmitting] - ); - - const thirdStep = useMemo( - () => ({ - title: i18n.STEP_THREE_TITLE, - children: ( - <Container> - <Connector - hideConnectorServiceNowSir={hideConnectorServiceNowSir} - isLoading={isSubmitting} - /> - </Container> - ), - }), - [hideConnectorServiceNowSir, isSubmitting] - ); - - const allSteps = useMemo(() => [firstStep, secondStep, thirdStep], [ - firstStep, - secondStep, - thirdStep, - ]); - - return ( - <> - {isSubmitting && <MySpinner data-test-subj="create-case-loading-spinner" size="xl" />} - {withSteps ? ( - <EuiSteps - headingElement="h2" - steps={allSteps} - data-test-subj={'case-creation-form-steps'} - /> - ) : ( - <> - {firstStep.children} - {secondStep.children} - {thirdStep.children} - </> - )} - </> - ); - } -); - -CreateCaseForm.displayName = 'CreateCaseForm'; diff --git a/x-pack/plugins/cases/public/components/create/form_context.test.tsx b/x-pack/plugins/cases/public/components/create/form_context.test.tsx deleted file mode 100644 index 207ff6207e09..000000000000 --- a/x-pack/plugins/cases/public/components/create/form_context.test.tsx +++ /dev/null @@ -1,682 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { mount, ReactWrapper } from 'enzyme'; -import { act, waitFor } from '@testing-library/react'; -import { EuiComboBox, EuiComboBoxOptionOption } from '@elastic/eui'; - -import { ConnectorTypes } from '../../../common'; -import { TestProviders } from '../../common/mock'; -import { usePostCase } from '../../containers/use_post_case'; -import { useGetTags } from '../../containers/use_get_tags'; -import { useConnectors } from '../../containers/configure/use_connectors'; -import { useCaseConfigure } from '../../containers/configure/use_configure'; -import { connectorsMock } from '../../containers/configure/mock'; -import { useGetIncidentTypes } from '../connectors/resilient/use_get_incident_types'; -import { useGetSeverity } from '../connectors/resilient/use_get_severity'; -import { useGetIssueTypes } from '../connectors/jira/use_get_issue_types'; -import { useGetChoices } from '../connectors/servicenow/use_get_choices'; -import { useGetFieldsByIssueType } from '../connectors/jira/use_get_fields_by_issue_type'; -import { useCaseConfigureResponse } from '../configure_cases/__mock__'; -import { - sampleConnectorData, - sampleData, - sampleTags, - useGetIncidentTypesResponse, - useGetSeverityResponse, - useGetIssueTypesResponse, - useGetFieldsByIssueTypeResponse, - useGetChoicesResponse, -} from './mock'; -import { FormContext } from './form_context'; -import { CreateCaseForm } from './form'; -import { SubmitCaseButton } from './submit_button'; -import { usePostPushToService } from '../../containers/use_post_push_to_service'; - -const sampleId = 'case-id'; - -jest.mock('../../containers/use_post_case'); -jest.mock('../../containers/use_post_push_to_service'); -jest.mock('../../containers/use_get_tags'); -jest.mock('../../containers/configure/use_connectors'); -jest.mock('../../containers/configure/use_configure'); -jest.mock('../connectors/resilient/use_get_incident_types'); -jest.mock('../connectors/resilient/use_get_severity'); -jest.mock('../connectors/jira/use_get_issue_types'); -jest.mock('../connectors/jira/use_get_fields_by_issue_type'); -jest.mock('../connectors/jira/use_get_single_issue'); -jest.mock('../connectors/jira/use_get_issues'); -jest.mock('../connectors/servicenow/use_get_choices'); - -const useConnectorsMock = useConnectors as jest.Mock; -const useCaseConfigureMock = useCaseConfigure as jest.Mock; -const usePostCaseMock = usePostCase as jest.Mock; -const usePostPushToServiceMock = usePostPushToService as jest.Mock; -const useGetIncidentTypesMock = useGetIncidentTypes as jest.Mock; -const useGetSeverityMock = useGetSeverity as jest.Mock; -const useGetIssueTypesMock = useGetIssueTypes as jest.Mock; -const useGetFieldsByIssueTypeMock = useGetFieldsByIssueType as jest.Mock; -const useGetChoicesMock = useGetChoices as jest.Mock; -const postCase = jest.fn(); -const pushCaseToExternalService = jest.fn(); - -const defaultPostCase = { - isLoading: false, - isError: false, - postCase, -}; - -const defaultPostPushToService = { - isLoading: false, - isError: false, - pushCaseToExternalService, -}; - -const fillForm = (wrapper: ReactWrapper) => { - wrapper - .find(`[data-test-subj="caseTitle"] input`) - .first() - .simulate('change', { target: { value: sampleData.title } }); - - wrapper - .find(`[data-test-subj="caseDescription"] textarea`) - .first() - .simulate('change', { target: { value: sampleData.description } }); - - act(() => { - ((wrapper.find(EuiComboBox).props() as unknown) as { - onChange: (a: EuiComboBoxOptionOption[]) => void; - }).onChange(sampleTags.map((tag) => ({ label: tag }))); - }); -}; - -describe('Create case', () => { - const fetchTags = jest.fn(); - const onFormSubmitSuccess = jest.fn(); - const afterCaseCreated = jest.fn(); - - beforeEach(() => { - jest.resetAllMocks(); - postCase.mockResolvedValue({ - id: sampleId, - ...sampleData, - }); - usePostCaseMock.mockImplementation(() => defaultPostCase); - usePostPushToServiceMock.mockImplementation(() => defaultPostPushToService); - useConnectorsMock.mockReturnValue(sampleConnectorData); - useCaseConfigureMock.mockImplementation(() => useCaseConfigureResponse); - useGetIncidentTypesMock.mockReturnValue(useGetIncidentTypesResponse); - useGetSeverityMock.mockReturnValue(useGetSeverityResponse); - useGetIssueTypesMock.mockReturnValue(useGetIssueTypesResponse); - useGetFieldsByIssueTypeMock.mockReturnValue(useGetFieldsByIssueTypeResponse); - useGetChoicesMock.mockReturnValue(useGetChoicesResponse); - - (useGetTags as jest.Mock).mockImplementation(() => ({ - tags: sampleTags, - fetchTags, - })); - }); - - describe('Step 1 - Case Fields', () => { - it('it renders', async () => { - const wrapper = mount( - <TestProviders> - <FormContext onSuccess={onFormSubmitSuccess}> - <CreateCaseForm /> - <SubmitCaseButton /> - </FormContext> - </TestProviders> - ); - - expect(wrapper.find(`[data-test-subj="caseTitle"]`).first().exists()).toBeTruthy(); - expect(wrapper.find(`[data-test-subj="caseDescription"]`).first().exists()).toBeTruthy(); - expect(wrapper.find(`[data-test-subj="caseTags"]`).first().exists()).toBeTruthy(); - expect(wrapper.find(`[data-test-subj="caseConnectors"]`).first().exists()).toBeTruthy(); - expect( - wrapper.find(`[data-test-subj="case-creation-form-steps"]`).first().exists() - ).toBeTruthy(); - }); - - it('should post case on submit click', async () => { - useConnectorsMock.mockReturnValue({ - ...sampleConnectorData, - connectors: connectorsMock, - }); - - const wrapper = mount( - <TestProviders> - <FormContext onSuccess={onFormSubmitSuccess}> - <CreateCaseForm /> - <SubmitCaseButton /> - </FormContext> - </TestProviders> - ); - - fillForm(wrapper); - wrapper.find(`[data-test-subj="create-case-submit"]`).first().simulate('click'); - await waitFor(() => expect(postCase).toBeCalledWith(sampleData)); - }); - - it('should toggle sync settings', async () => { - useConnectorsMock.mockReturnValue({ - ...sampleConnectorData, - connectors: connectorsMock, - }); - - const wrapper = mount( - <TestProviders> - <FormContext onSuccess={onFormSubmitSuccess}> - <CreateCaseForm /> - <SubmitCaseButton /> - </FormContext> - </TestProviders> - ); - - fillForm(wrapper); - wrapper.find('[data-test-subj="caseSyncAlerts"] button').first().simulate('click'); - wrapper.find(`[data-test-subj="create-case-submit"]`).first().simulate('click'); - - await waitFor(() => - expect(postCase).toBeCalledWith({ ...sampleData, settings: { syncAlerts: false } }) - ); - }); - - it('it should select the default connector set in the configuration', async () => { - useCaseConfigureMock.mockImplementation(() => ({ - ...useCaseConfigureResponse, - connector: { - id: 'servicenow-1', - name: 'SN', - type: ConnectorTypes.serviceNowITSM, - fields: null, - }, - persistLoading: false, - })); - - useConnectorsMock.mockReturnValue({ - ...sampleConnectorData, - connectors: connectorsMock, - }); - - const wrapper = mount( - <TestProviders> - <FormContext onSuccess={onFormSubmitSuccess}> - <CreateCaseForm /> - <SubmitCaseButton /> - </FormContext> - </TestProviders> - ); - - fillForm(wrapper); - await act(async () => { - wrapper.find(`[data-test-subj="create-case-submit"]`).first().simulate('click'); - }); - - await waitFor(() => - expect(postCase).toBeCalledWith({ - ...sampleData, - connector: { - fields: { - impact: null, - severity: null, - urgency: null, - category: null, - subcategory: null, - }, - id: 'servicenow-1', - name: 'My Connector', - type: '.servicenow', - }, - }) - ); - }); - - it('it should default to none if the default connector does not exist in connectors', async () => { - useCaseConfigureMock.mockImplementation(() => ({ - ...useCaseConfigureResponse, - connector: { - id: 'not-exist', - name: 'SN', - type: ConnectorTypes.serviceNowITSM, - fields: null, - }, - persistLoading: false, - })); - - useConnectorsMock.mockReturnValue({ - ...sampleConnectorData, - connectors: connectorsMock, - }); - - const wrapper = mount( - <TestProviders> - <FormContext onSuccess={onFormSubmitSuccess}> - <CreateCaseForm /> - <SubmitCaseButton /> - </FormContext> - </TestProviders> - ); - - fillForm(wrapper); - wrapper.find(`[data-test-subj="create-case-submit"]`).first().simulate('click'); - await waitFor(() => { - expect(postCase).toBeCalledWith(sampleData); - expect(pushCaseToExternalService).not.toHaveBeenCalled(); - }); - }); - }); - - describe('Step 2 - Connector Fields', () => { - it(`it should submit and push to Jira connector`, async () => { - useConnectorsMock.mockReturnValue({ - ...sampleConnectorData, - connectors: connectorsMock, - }); - - const wrapper = mount( - <TestProviders> - <FormContext onSuccess={onFormSubmitSuccess}> - <CreateCaseForm /> - <SubmitCaseButton /> - </FormContext> - </TestProviders> - ); - - fillForm(wrapper); - expect(wrapper.find(`[data-test-subj="connector-fields-jira"]`).exists()).toBeFalsy(); - wrapper.find('button[data-test-subj="dropdown-connectors"]').simulate('click'); - wrapper.find(`button[data-test-subj="dropdown-connector-jira-1"]`).simulate('click'); - - await waitFor(() => { - wrapper.update(); - expect(wrapper.find(`[data-test-subj="connector-fields-jira"]`).exists()).toBeTruthy(); - }); - - wrapper - .find('select[data-test-subj="issueTypeSelect"]') - .first() - .simulate('change', { - target: { value: '10007' }, - }); - - wrapper - .find('select[data-test-subj="prioritySelect"]') - .first() - .simulate('change', { - target: { value: '2' }, - }); - - wrapper.find(`[data-test-subj="create-case-submit"]`).first().simulate('click'); - - await waitFor(() => { - expect(postCase).toBeCalledWith({ - ...sampleData, - connector: { - id: 'jira-1', - name: 'Jira', - type: '.jira', - fields: { issueType: '10007', parent: null, priority: '2' }, - }, - }); - expect(pushCaseToExternalService).toHaveBeenCalledWith({ - caseId: sampleId, - connector: { - id: 'jira-1', - name: 'Jira', - type: '.jira', - fields: { issueType: '10007', parent: null, priority: '2' }, - }, - }); - expect(onFormSubmitSuccess).toHaveBeenCalledWith({ - id: sampleId, - ...sampleData, - }); - }); - }); - - it(`it should submit and push to resilient connector`, async () => { - useConnectorsMock.mockReturnValue({ - ...sampleConnectorData, - connectors: connectorsMock, - }); - - const wrapper = mount( - <TestProviders> - <FormContext onSuccess={onFormSubmitSuccess}> - <CreateCaseForm /> - <SubmitCaseButton /> - </FormContext> - </TestProviders> - ); - - fillForm(wrapper); - expect(wrapper.find(`[data-test-subj="connector-fields-resilient"]`).exists()).toBeFalsy(); - wrapper.find('button[data-test-subj="dropdown-connectors"]').simulate('click'); - wrapper.find(`button[data-test-subj="dropdown-connector-resilient-2"]`).simulate('click'); - - await waitFor(() => { - wrapper.update(); - expect(wrapper.find(`[data-test-subj="connector-fields-resilient"]`).exists()).toBeTruthy(); - }); - - act(() => { - ((wrapper.find(EuiComboBox).at(1).props() as unknown) as { - onChange: (a: EuiComboBoxOptionOption[]) => void; - }).onChange([{ value: '19', label: 'Denial of Service' }]); - }); - - wrapper - .find('select[data-test-subj="severitySelect"]') - .first() - .simulate('change', { - target: { value: '4' }, - }); - - wrapper.find(`[data-test-subj="create-case-submit"]`).first().simulate('click'); - - await waitFor(() => { - expect(postCase).toBeCalledWith({ - ...sampleData, - connector: { - id: 'resilient-2', - name: 'My Connector 2', - type: '.resilient', - fields: { incidentTypes: ['19'], severityCode: '4' }, - }, - }); - - expect(pushCaseToExternalService).toHaveBeenCalledWith({ - caseId: sampleId, - connector: { - id: 'resilient-2', - name: 'My Connector 2', - type: '.resilient', - fields: { incidentTypes: ['19'], severityCode: '4' }, - }, - }); - - expect(onFormSubmitSuccess).toHaveBeenCalledWith({ - id: sampleId, - ...sampleData, - }); - }); - }); - - it(`it should submit and push to servicenow itsm connector`, async () => { - useConnectorsMock.mockReturnValue({ - ...sampleConnectorData, - connectors: connectorsMock, - }); - - const wrapper = mount( - <TestProviders> - <FormContext onSuccess={onFormSubmitSuccess}> - <CreateCaseForm /> - <SubmitCaseButton /> - </FormContext> - </TestProviders> - ); - - fillForm(wrapper); - expect(wrapper.find(`[data-test-subj="connector-fields-sn-itsm"]`).exists()).toBeFalsy(); - wrapper.find('button[data-test-subj="dropdown-connectors"]').simulate('click'); - wrapper.find(`button[data-test-subj="dropdown-connector-servicenow-1"]`).simulate('click'); - - await waitFor(() => { - wrapper.update(); - expect(wrapper.find(`[data-test-subj="connector-fields-sn-itsm"]`).exists()).toBeTruthy(); - }); - - ['severitySelect', 'urgencySelect', 'impactSelect'].forEach((subj) => { - wrapper - .find(`select[data-test-subj="${subj}"]`) - .first() - .simulate('change', { - target: { value: '2' }, - }); - }); - - wrapper - .find('select[data-test-subj="categorySelect"]') - .first() - .simulate('change', { - target: { value: 'software' }, - }); - - wrapper - .find('select[data-test-subj="subcategorySelect"]') - .first() - .simulate('change', { - target: { value: 'os' }, - }); - - wrapper.find(`[data-test-subj="create-case-submit"]`).first().simulate('click'); - - await waitFor(() => { - expect(postCase).toBeCalledWith({ - ...sampleData, - connector: { - id: 'servicenow-1', - name: 'My Connector', - type: '.servicenow', - fields: { - impact: '2', - severity: '2', - urgency: '2', - category: 'software', - subcategory: 'os', - }, - }, - }); - - expect(pushCaseToExternalService).toHaveBeenCalledWith({ - caseId: sampleId, - connector: { - id: 'servicenow-1', - name: 'My Connector', - type: '.servicenow', - fields: { - impact: '2', - severity: '2', - urgency: '2', - category: 'software', - subcategory: 'os', - }, - }, - }); - - expect(onFormSubmitSuccess).toHaveBeenCalledWith({ - id: sampleId, - ...sampleData, - }); - }); - }); - - it(`it should submit and push to servicenow sir connector`, async () => { - useConnectorsMock.mockReturnValue({ - ...sampleConnectorData, - connectors: connectorsMock, - }); - - const wrapper = mount( - <TestProviders> - <FormContext onSuccess={onFormSubmitSuccess}> - <CreateCaseForm /> - <SubmitCaseButton /> - </FormContext> - </TestProviders> - ); - - fillForm(wrapper); - expect(wrapper.find(`[data-test-subj="connector-fields-sn-sir"]`).exists()).toBeFalsy(); - wrapper.find('button[data-test-subj="dropdown-connectors"]').simulate('click'); - wrapper.find(`button[data-test-subj="dropdown-connector-servicenow-sir"]`).simulate('click'); - - await waitFor(() => { - wrapper.update(); - expect(wrapper.find(`[data-test-subj="connector-fields-sn-sir"]`).exists()).toBeTruthy(); - }); - - wrapper - .find('[data-test-subj="destIpCheckbox"] input') - .first() - .simulate('change', { target: { checked: false } }); - - wrapper - .find('select[data-test-subj="prioritySelect"]') - .first() - .simulate('change', { - target: { value: '1' }, - }); - - wrapper - .find('select[data-test-subj="categorySelect"]') - .first() - .simulate('change', { - target: { value: 'Denial of Service' }, - }); - - wrapper - .find('select[data-test-subj="subcategorySelect"]') - .first() - .simulate('change', { - target: { value: '26' }, - }); - - wrapper.find(`[data-test-subj="create-case-submit"]`).first().simulate('click'); - - await waitFor(() => { - expect(postCase).toBeCalledWith({ - ...sampleData, - connector: { - id: 'servicenow-sir', - name: 'My Connector SIR', - type: '.servicenow-sir', - fields: { - destIp: false, - sourceIp: true, - malwareHash: true, - malwareUrl: true, - priority: '1', - category: 'Denial of Service', - subcategory: '26', - }, - }, - }); - - expect(pushCaseToExternalService).toHaveBeenCalledWith({ - caseId: sampleId, - connector: { - id: 'servicenow-sir', - name: 'My Connector SIR', - type: '.servicenow-sir', - fields: { - destIp: false, - sourceIp: true, - malwareHash: true, - malwareUrl: true, - priority: '1', - category: 'Denial of Service', - subcategory: '26', - }, - }, - }); - - expect(onFormSubmitSuccess).toHaveBeenCalledWith({ - id: sampleId, - ...sampleData, - }); - }); - }); - }); - - it(`it should call afterCaseCreated`, async () => { - useConnectorsMock.mockReturnValue({ - ...sampleConnectorData, - connectors: connectorsMock, - }); - - const wrapper = mount( - <TestProviders> - <FormContext onSuccess={onFormSubmitSuccess} afterCaseCreated={afterCaseCreated}> - <CreateCaseForm /> - <SubmitCaseButton /> - </FormContext> - </TestProviders> - ); - - fillForm(wrapper); - expect(wrapper.find(`[data-test-subj="connector-fields-jira"]`).exists()).toBeFalsy(); - wrapper.find('button[data-test-subj="dropdown-connectors"]').simulate('click'); - wrapper.find(`button[data-test-subj="dropdown-connector-jira-1"]`).simulate('click'); - - await waitFor(() => { - wrapper.update(); - expect(wrapper.find(`[data-test-subj="connector-fields-jira"]`).exists()).toBeTruthy(); - }); - - wrapper.find(`[data-test-subj="create-case-submit"]`).first().simulate('click'); - await waitFor(() => { - expect(afterCaseCreated).toHaveBeenCalledWith({ - id: sampleId, - ...sampleData, - }); - }); - }); - - it(`it should call callbacks in correct order`, async () => { - useConnectorsMock.mockReturnValue({ - ...sampleConnectorData, - connectors: connectorsMock, - }); - - const wrapper = mount( - <TestProviders> - <FormContext onSuccess={onFormSubmitSuccess} afterCaseCreated={afterCaseCreated}> - <CreateCaseForm /> - <SubmitCaseButton /> - </FormContext> - </TestProviders> - ); - - fillForm(wrapper); - expect(wrapper.find(`[data-test-subj="connector-fields-jira"]`).exists()).toBeFalsy(); - wrapper.find('button[data-test-subj="dropdown-connectors"]').simulate('click'); - wrapper.find(`button[data-test-subj="dropdown-connector-jira-1"]`).simulate('click'); - - await waitFor(() => { - wrapper.update(); - expect(wrapper.find(`[data-test-subj="connector-fields-jira"]`).exists()).toBeTruthy(); - }); - - wrapper.find(`[data-test-subj="create-case-submit"]`).first().simulate('click'); - await waitFor(() => { - expect(postCase).toHaveBeenCalled(); - expect(afterCaseCreated).toHaveBeenCalled(); - expect(pushCaseToExternalService).toHaveBeenCalled(); - expect(onFormSubmitSuccess).toHaveBeenCalled(); - }); - - const postCaseOrder = postCase.mock.invocationCallOrder[0]; - const afterCaseOrder = afterCaseCreated.mock.invocationCallOrder[0]; - const pushCaseToExternalServiceOrder = pushCaseToExternalService.mock.invocationCallOrder[0]; - const onFormSubmitSuccessOrder = onFormSubmitSuccess.mock.invocationCallOrder[0]; - - expect( - postCaseOrder < afterCaseOrder && - postCaseOrder < pushCaseToExternalServiceOrder && - postCaseOrder < onFormSubmitSuccessOrder - ).toBe(true); - - expect( - afterCaseOrder < pushCaseToExternalServiceOrder && afterCaseOrder < onFormSubmitSuccessOrder - ).toBe(true); - - expect(pushCaseToExternalServiceOrder < onFormSubmitSuccessOrder).toBe(true); - }); -}); diff --git a/x-pack/plugins/cases/public/components/create/form_context.tsx b/x-pack/plugins/cases/public/components/create/form_context.tsx deleted file mode 100644 index e84f451ab421..000000000000 --- a/x-pack/plugins/cases/public/components/create/form_context.tsx +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { useCallback, useEffect, useMemo } from 'react'; -import { schema, FormProps } from './schema'; -import { Form, useForm } from '../../common/shared_imports'; -import { - getConnectorById, - getNoneConnector, - normalizeActionConnector, -} from '../configure_cases/utils'; -import { usePostCase } from '../../containers/use_post_case'; -import { usePostPushToService } from '../../containers/use_post_push_to_service'; - -import { useConnectors } from '../../containers/configure/use_connectors'; -import { useCaseConfigure } from '../../containers/configure/use_configure'; -import { Case } from '../../containers/types'; -import { CaseType, ConnectorTypes } from '../../../common'; - -const initialCaseValue: FormProps = { - description: '', - tags: [], - title: '', - connectorId: 'none', - fields: null, - syncAlerts: true, -}; - -interface Props { - afterCaseCreated?: (theCase: Case) => Promise<void>; - caseType?: CaseType; - hideConnectorServiceNowSir?: boolean; - onSuccess?: (theCase: Case) => Promise<void>; -} - -export const FormContext: React.FC<Props> = ({ - afterCaseCreated, - caseType = CaseType.individual, - children, - hideConnectorServiceNowSir, - onSuccess, -}) => { - const { connectors } = useConnectors(); - const { connector: configurationConnector } = useCaseConfigure(); - const { postCase } = usePostCase(); - const { pushCaseToExternalService } = usePostPushToService(); - - const connectorId = useMemo(() => { - if ( - hideConnectorServiceNowSir && - configurationConnector.type === ConnectorTypes.serviceNowSIR - ) { - return 'none'; - } - return connectors.some((connector) => connector.id === configurationConnector.id) - ? configurationConnector.id - : 'none'; - }, [ - configurationConnector.id, - configurationConnector.type, - connectors, - hideConnectorServiceNowSir, - ]); - - const submitCase = useCallback( - async ( - { connectorId: dataConnectorId, fields, syncAlerts, ...dataWithoutConnectorId }, - isValid - ) => { - if (isValid) { - const caseConnector = getConnectorById(dataConnectorId, connectors); - - const connectorToUpdate = caseConnector - ? normalizeActionConnector(caseConnector, fields) - : getNoneConnector(); - - const updatedCase = await postCase({ - ...dataWithoutConnectorId, - type: caseType, - connector: connectorToUpdate, - settings: { syncAlerts }, - }); - - if (afterCaseCreated && updatedCase) { - await afterCaseCreated(updatedCase); - } - - if (updatedCase?.id && dataConnectorId !== 'none') { - await pushCaseToExternalService({ - caseId: updatedCase.id, - connector: connectorToUpdate, - }); - } - - if (onSuccess && updatedCase) { - await onSuccess(updatedCase); - } - } - }, - [caseType, connectors, postCase, onSuccess, pushCaseToExternalService, afterCaseCreated] - ); - - const { form } = useForm<FormProps>({ - defaultValue: initialCaseValue, - options: { stripEmptyFields: false }, - schema, - onSubmit: submitCase, - }); - const { setFieldValue } = form; - // Set the selected connector to the configuration connector - useEffect(() => setFieldValue('connectorId', connectorId), [connectorId, setFieldValue]); - - return <Form form={form}>{children}</Form>; -}; - -FormContext.displayName = 'FormContext'; diff --git a/x-pack/plugins/cases/public/components/create/index.test.tsx b/x-pack/plugins/cases/public/components/create/index.test.tsx deleted file mode 100644 index e82af8edc633..000000000000 --- a/x-pack/plugins/cases/public/components/create/index.test.tsx +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { mount, ReactWrapper } from 'enzyme'; -import { act, waitFor } from '@testing-library/react'; -import { EuiComboBox, EuiComboBoxOptionOption } from '@elastic/eui'; - -import { TestProviders } from '../../common/mock'; -import { useGetTags } from '../../containers/use_get_tags'; -import { useConnectors } from '../../containers/configure/use_connectors'; -import { useCaseConfigure } from '../../containers/configure/use_configure'; -import { useGetIncidentTypes } from '../connectors/resilient/use_get_incident_types'; -import { useGetSeverity } from '../connectors/resilient/use_get_severity'; -import { useGetIssueTypes } from '../connectors/jira/use_get_issue_types'; -import { useGetFieldsByIssueType } from '../connectors/jira/use_get_fields_by_issue_type'; -import { useCaseConfigureResponse } from '../configure_cases/__mock__'; -import { - sampleConnectorData, - sampleData, - sampleTags, - useGetIncidentTypesResponse, - useGetSeverityResponse, - useGetIssueTypesResponse, - useGetFieldsByIssueTypeResponse, -} from './mock'; -import { CreateCase } from '.'; - -jest.mock('../../containers/api'); -jest.mock('../../containers/use_get_tags'); -jest.mock('../../containers/configure/use_connectors'); -jest.mock('../../containers/configure/use_configure'); -jest.mock('../connectors/resilient/use_get_incident_types'); -jest.mock('../connectors/resilient/use_get_severity'); -jest.mock('../connectors/jira/use_get_issue_types'); -jest.mock('../connectors/jira/use_get_fields_by_issue_type'); -jest.mock('../connectors/jira/use_get_single_issue'); -jest.mock('../connectors/jira/use_get_issues'); - -const useConnectorsMock = useConnectors as jest.Mock; -const useCaseConfigureMock = useCaseConfigure as jest.Mock; -const useGetTagsMock = useGetTags as jest.Mock; -const useGetIncidentTypesMock = useGetIncidentTypes as jest.Mock; -const useGetSeverityMock = useGetSeverity as jest.Mock; -const useGetIssueTypesMock = useGetIssueTypes as jest.Mock; -const useGetFieldsByIssueTypeMock = useGetFieldsByIssueType as jest.Mock; -const fetchTags = jest.fn(); - -const fillForm = (wrapper: ReactWrapper) => { - wrapper - .find(`[data-test-subj="caseTitle"] input`) - .first() - .simulate('change', { target: { value: sampleData.title } }); - - wrapper - .find(`[data-test-subj="caseDescription"] textarea`) - .first() - .simulate('change', { target: { value: sampleData.description } }); - - act(() => { - ((wrapper.find(EuiComboBox).props() as unknown) as { - onChange: (a: EuiComboBoxOptionOption[]) => void; - }).onChange(sampleTags.map((tag) => ({ label: tag }))); - }); -}; - -const defaultProps = { - onCancel: jest.fn(), - onSuccess: jest.fn(), -}; - -describe('CreateCase case', () => { - beforeEach(() => { - jest.resetAllMocks(); - useConnectorsMock.mockReturnValue(sampleConnectorData); - useCaseConfigureMock.mockImplementation(() => useCaseConfigureResponse); - useGetIncidentTypesMock.mockReturnValue(useGetIncidentTypesResponse); - useGetSeverityMock.mockReturnValue(useGetSeverityResponse); - useGetIssueTypesMock.mockReturnValue(useGetIssueTypesResponse); - useGetFieldsByIssueTypeMock.mockReturnValue(useGetFieldsByIssueTypeResponse); - useGetTagsMock.mockImplementation(() => ({ - tags: sampleTags, - fetchTags, - })); - }); - - it('it renders', async () => { - const wrapper = mount( - <TestProviders> - <CreateCase {...defaultProps} /> - </TestProviders> - ); - - expect(wrapper.find(`[data-test-subj="create-case-submit"]`).exists()).toBeTruthy(); - expect(wrapper.find(`[data-test-subj="create-case-cancel"]`).exists()).toBeTruthy(); - }); - - it('should call cancel on cancel click', async () => { - const wrapper = mount( - <TestProviders> - <CreateCase {...defaultProps} /> - </TestProviders> - ); - - wrapper.find(`[data-test-subj="create-case-cancel"]`).first().simulate('click'); - expect(defaultProps.onCancel).toHaveBeenCalled(); - }); - - it('should redirect to new case when posting the case', async () => { - const wrapper = mount( - <TestProviders> - <CreateCase {...defaultProps} /> - </TestProviders> - ); - - fillForm(wrapper); - wrapper.find(`[data-test-subj="create-case-submit"]`).first().simulate('click'); - await waitFor(() => { - expect(defaultProps.onSuccess).toHaveBeenCalled(); - }); - }); -}); diff --git a/x-pack/plugins/cases/public/components/create/index.tsx b/x-pack/plugins/cases/public/components/create/index.tsx deleted file mode 100644 index 192effb6adb2..000000000000 --- a/x-pack/plugins/cases/public/components/create/index.tsx +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import styled from 'styled-components'; - -import { Field, getUseField } from '../../common/shared_imports'; -import * as i18n from './translations'; -import { CreateCaseForm } from './form'; -import { FormContext } from './form_context'; -import { SubmitCaseButton } from './submit_button'; -import { Case } from '../../containers/types'; - -export const CommonUseField = getUseField({ component: Field }); - -const Container = styled.div` - ${({ theme }) => ` - margin-top: ${theme.eui.euiSize}; - `} -`; - -export interface CreateCaseProps { - afterCaseCreated?: (theCase: Case) => Promise<void>; - onCancel: () => void; - onSuccess: (theCase: Case) => Promise<void>; -} - -export const CreateCase = ({ afterCaseCreated, onCancel, onSuccess }: CreateCaseProps) => ( - <FormContext afterCaseCreated={afterCaseCreated} onSuccess={onSuccess}> - <CreateCaseForm /> - <Container> - <EuiFlexGroup alignItems="center" justifyContent="flexEnd" gutterSize="xs" responsive={false}> - <EuiFlexItem grow={false}> - <EuiButtonEmpty - data-test-subj="create-case-cancel" - size="s" - onClick={onCancel} - iconType="cross" - > - {i18n.CANCEL} - </EuiButtonEmpty> - </EuiFlexItem> - <EuiFlexItem grow={false}> - <SubmitCaseButton /> - </EuiFlexItem> - </EuiFlexGroup> - </Container> - </FormContext> -); - -// eslint-disable-next-line import/no-default-export -export { CreateCase as default }; diff --git a/x-pack/plugins/cases/public/components/create/mock.ts b/x-pack/plugins/cases/public/components/create/mock.ts deleted file mode 100644 index eb40fa097d3c..000000000000 --- a/x-pack/plugins/cases/public/components/create/mock.ts +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { CasePostRequest, CaseType, ConnectorTypes } from '../../../common'; -import { choices } from '../connectors/mock'; - -export const sampleTags = ['coke', 'pepsi']; -export const sampleData: CasePostRequest = { - description: 'what a great description', - tags: sampleTags, - title: 'what a cool title', - type: CaseType.individual, - connector: { - fields: null, - id: 'none', - name: 'none', - type: ConnectorTypes.none, - }, - settings: { - syncAlerts: true, - }, -}; - -export const sampleConnectorData = { loading: false, connectors: [] }; - -export const useGetIncidentTypesResponse = { - isLoading: false, - incidentTypes: [ - { - id: 19, - name: 'Malware', - }, - { - id: 21, - name: 'Denial of Service', - }, - ], -}; - -export const useGetSeverityResponse = { - isLoading: false, - severity: [ - { - id: 4, - name: 'Low', - }, - { - id: 5, - name: 'Medium', - }, - { - id: 6, - name: 'High', - }, - ], -}; - -export const useGetIssueTypesResponse = { - isLoading: false, - issueTypes: [ - { - id: '10006', - name: 'Task', - }, - { - id: '10007', - name: 'Bug', - }, - ], -}; - -export const useGetFieldsByIssueTypeResponse = { - isLoading: false, - fields: { - summary: { allowedValues: [], defaultValue: {} }, - labels: { allowedValues: [], defaultValue: {} }, - description: { allowedValues: [], defaultValue: {} }, - priority: { - allowedValues: [ - { - name: 'Medium', - id: '3', - }, - { - name: 'Low', - id: '2', - }, - ], - defaultValue: { name: 'Medium', id: '3' }, - }, - }, -}; - -export const useGetChoicesResponse = { - isLoading: false, - choices, -}; diff --git a/x-pack/plugins/cases/public/components/create/optional_field_label/index.test.tsx b/x-pack/plugins/cases/public/components/create/optional_field_label/index.test.tsx deleted file mode 100644 index 4b6d5f90513e..000000000000 --- a/x-pack/plugins/cases/public/components/create/optional_field_label/index.test.tsx +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { mount } from 'enzyme'; - -import { OptionalFieldLabel } from '.'; - -describe('OptionalFieldLabel', () => { - it('it renders correctly', async () => { - const wrapper = mount(OptionalFieldLabel); - expect(wrapper.find('[data-test-subj="form-optional-field-label"]').first().text()).toBe( - 'Optional' - ); - }); -}); diff --git a/x-pack/plugins/cases/public/components/create/optional_field_label/index.tsx b/x-pack/plugins/cases/public/components/create/optional_field_label/index.tsx deleted file mode 100644 index ea994b221996..000000000000 --- a/x-pack/plugins/cases/public/components/create/optional_field_label/index.tsx +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiText } from '@elastic/eui'; -import React from 'react'; - -import * as i18n from '../../../common/translations'; - -export const OptionalFieldLabel = ( - <EuiText color="subdued" size="xs" data-test-subj="form-optional-field-label"> - {i18n.OPTIONAL} - </EuiText> -); diff --git a/x-pack/plugins/cases/public/components/create/schema.tsx b/x-pack/plugins/cases/public/components/create/schema.tsx deleted file mode 100644 index 7ca1e2e06154..000000000000 --- a/x-pack/plugins/cases/public/components/create/schema.tsx +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { CasePostRequest, ConnectorTypeFields } from '../../../common'; -import { FIELD_TYPES, fieldValidators, FormSchema } from '../../common/shared_imports'; -import * as i18n from './translations'; - -import { OptionalFieldLabel } from './optional_field_label'; -const { emptyField } = fieldValidators; - -export const schemaTags = { - type: FIELD_TYPES.COMBO_BOX, - label: i18n.TAGS, - helpText: i18n.TAGS_HELP, - labelAppend: OptionalFieldLabel, -}; - -export type FormProps = Omit<CasePostRequest, 'connector' | 'settings'> & { - connectorId: string; - fields: ConnectorTypeFields['fields']; - syncAlerts: boolean; -}; - -export const schema: FormSchema<FormProps> = { - title: { - type: FIELD_TYPES.TEXT, - label: i18n.NAME, - validations: [ - { - validator: emptyField(i18n.TITLE_REQUIRED), - }, - ], - }, - description: { - label: i18n.DESCRIPTION, - validations: [ - { - validator: emptyField(i18n.DESCRIPTION_REQUIRED), - }, - ], - }, - tags: schemaTags, - connectorId: { - type: FIELD_TYPES.SUPER_SELECT, - label: i18n.CONNECTORS, - defaultValue: 'none', - }, - fields: {}, - syncAlerts: { - helpText: i18n.SYNC_ALERTS_HELP, - type: FIELD_TYPES.TOGGLE, - defaultValue: true, - }, -}; diff --git a/x-pack/plugins/cases/public/components/create/submit_button.test.tsx b/x-pack/plugins/cases/public/components/create/submit_button.test.tsx deleted file mode 100644 index dd67c8170dc3..000000000000 --- a/x-pack/plugins/cases/public/components/create/submit_button.test.tsx +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { mount } from 'enzyme'; -import { act, waitFor } from '@testing-library/react'; - -import { useForm, Form } from '../../common/shared_imports'; -import { SubmitCaseButton } from './submit_button'; -import { schema, FormProps } from './schema'; - -describe('SubmitCaseButton', () => { - const onSubmit = jest.fn(); - - const MockHookWrapperComponent: React.FC = ({ children }) => { - const { form } = useForm<FormProps>({ - defaultValue: { title: 'My title' }, - schema: { - title: schema.title, - }, - onSubmit, - }); - - return <Form form={form}>{children}</Form>; - }; - - beforeEach(() => { - jest.resetAllMocks(); - }); - - it('it renders', async () => { - const wrapper = mount( - <MockHookWrapperComponent> - <SubmitCaseButton /> - </MockHookWrapperComponent> - ); - - expect(wrapper.find(`[data-test-subj="create-case-submit"]`).exists()).toBeTruthy(); - }); - - it('it submits', async () => { - const wrapper = mount( - <MockHookWrapperComponent> - <SubmitCaseButton /> - </MockHookWrapperComponent> - ); - - await act(async () => { - wrapper.find(`[data-test-subj="create-case-submit"]`).first().simulate('click'); - }); - - await waitFor(() => expect(onSubmit).toBeCalled()); - }); - - it('it disables when submitting', async () => { - const wrapper = mount( - <MockHookWrapperComponent> - <SubmitCaseButton /> - </MockHookWrapperComponent> - ); - - await waitFor(() => { - wrapper.find(`[data-test-subj="create-case-submit"]`).first().simulate('click'); - expect( - wrapper.find(`[data-test-subj="create-case-submit"]`).first().prop('isDisabled') - ).toBeTruthy(); - }); - }); - - it('it is loading when submitting', async () => { - const wrapper = mount( - <MockHookWrapperComponent> - <SubmitCaseButton /> - </MockHookWrapperComponent> - ); - - await waitFor(() => { - wrapper.find(`[data-test-subj="create-case-submit"]`).first().simulate('click'); - expect( - wrapper.find(`[data-test-subj="create-case-submit"]`).first().prop('isLoading') - ).toBeTruthy(); - }); - }); -}); diff --git a/x-pack/plugins/cases/public/components/create/submit_button.tsx b/x-pack/plugins/cases/public/components/create/submit_button.tsx deleted file mode 100644 index b5e58517e6ec..000000000000 --- a/x-pack/plugins/cases/public/components/create/submit_button.tsx +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { memo } from 'react'; -import { EuiButton } from '@elastic/eui'; - -import { useFormContext } from '../../common/shared_imports'; -import * as i18n from './translations'; - -const SubmitCaseButtonComponent: React.FC = () => { - const { submit, isSubmitting } = useFormContext(); - - return ( - <EuiButton - data-test-subj="create-case-submit" - fill - iconType="plusInCircle" - isDisabled={isSubmitting} - isLoading={isSubmitting} - onClick={submit} - > - {i18n.CREATE_CASE} - </EuiButton> - ); -}; - -export const SubmitCaseButton = memo(SubmitCaseButtonComponent); diff --git a/x-pack/plugins/cases/public/components/create/sync_alerts_toggle.test.tsx b/x-pack/plugins/cases/public/components/create/sync_alerts_toggle.test.tsx deleted file mode 100644 index b4a37f0abb51..000000000000 --- a/x-pack/plugins/cases/public/components/create/sync_alerts_toggle.test.tsx +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { mount } from 'enzyme'; -import { waitFor } from '@testing-library/react'; - -import { useForm, Form, FormHook } from '../../common/shared_imports'; -import { SyncAlertsToggle } from './sync_alerts_toggle'; -import { schema, FormProps } from './schema'; - -describe('SyncAlertsToggle', () => { - let globalForm: FormHook; - - const MockHookWrapperComponent: React.FC = ({ children }) => { - const { form } = useForm<FormProps>({ - defaultValue: { syncAlerts: true }, - schema: { - syncAlerts: schema.syncAlerts, - }, - }); - - globalForm = form; - - return <Form form={form}>{children}</Form>; - }; - - beforeEach(() => { - jest.resetAllMocks(); - }); - - it('it renders', async () => { - const wrapper = mount( - <MockHookWrapperComponent> - <SyncAlertsToggle isLoading={false} /> - </MockHookWrapperComponent> - ); - - expect(wrapper.find(`[data-test-subj="caseSyncAlerts"]`).exists()).toBeTruthy(); - }); - - it('it toggles the switch', async () => { - const wrapper = mount( - <MockHookWrapperComponent> - <SyncAlertsToggle isLoading={false} /> - </MockHookWrapperComponent> - ); - - wrapper.find('[data-test-subj="caseSyncAlerts"] button').first().simulate('click'); - - await waitFor(() => { - expect(globalForm.getFormData()).toEqual({ syncAlerts: false }); - }); - }); - - it('it shows the correct labels', async () => { - const wrapper = mount( - <MockHookWrapperComponent> - <SyncAlertsToggle isLoading={false} /> - </MockHookWrapperComponent> - ); - - expect(wrapper.find(`[data-test-subj="caseSyncAlerts"] .euiSwitch__label`).first().text()).toBe( - 'On' - ); - - wrapper.find('[data-test-subj="caseSyncAlerts"] button').first().simulate('click'); - - await waitFor(() => { - expect( - wrapper.find(`[data-test-subj="caseSyncAlerts"] .euiSwitch__label`).first().text() - ).toBe('Off'); - }); - }); -}); diff --git a/x-pack/plugins/cases/public/components/create/sync_alerts_toggle.tsx b/x-pack/plugins/cases/public/components/create/sync_alerts_toggle.tsx deleted file mode 100644 index bed8e6d18f5e..000000000000 --- a/x-pack/plugins/cases/public/components/create/sync_alerts_toggle.tsx +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { memo } from 'react'; -import { Field, getUseField, useFormData } from '../../common/shared_imports'; -import * as i18n from './translations'; - -const CommonUseField = getUseField({ component: Field }); - -interface Props { - isLoading: boolean; -} - -const SyncAlertsToggleComponent: React.FC<Props> = ({ isLoading }) => { - const [{ syncAlerts }] = useFormData({ watch: ['syncAlerts'] }); - return ( - <CommonUseField - path="syncAlerts" - componentProps={{ - idAria: 'caseSyncAlerts', - 'data-test-subj': 'caseSyncAlerts', - label: i18n.SYNC_ALERTS_LABEL, - euiFieldProps: { - disabled: isLoading, - label: syncAlerts ? i18n.SYNC_ALERTS_SWITCH_LABEL_ON : i18n.SYNC_ALERTS_SWITCH_LABEL_OFF, - }, - }} - /> - ); -}; - -SyncAlertsToggleComponent.displayName = 'SyncAlertsToggleComponent'; - -export const SyncAlertsToggle = memo(SyncAlertsToggleComponent); diff --git a/x-pack/plugins/cases/public/components/create/tags.test.tsx b/x-pack/plugins/cases/public/components/create/tags.test.tsx deleted file mode 100644 index 2eddb83dcac2..000000000000 --- a/x-pack/plugins/cases/public/components/create/tags.test.tsx +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { mount } from 'enzyme'; -import { EuiComboBox, EuiComboBoxOptionOption } from '@elastic/eui'; -import { waitFor } from '@testing-library/react'; - -import { useForm, Form, FormHook } from '../../common/shared_imports'; -import { useGetTags } from '../../containers/use_get_tags'; -import { Tags } from './tags'; -import { schema, FormProps } from './schema'; - -jest.mock('../../containers/use_get_tags'); -const useGetTagsMock = useGetTags as jest.Mock; - -describe('Tags', () => { - let globalForm: FormHook; - - const MockHookWrapperComponent: React.FC = ({ children }) => { - const { form } = useForm<FormProps>({ - defaultValue: { tags: [] }, - schema: { - tags: schema.tags, - }, - }); - - globalForm = form; - - return <Form form={form}>{children}</Form>; - }; - - beforeEach(() => { - jest.resetAllMocks(); - useGetTagsMock.mockReturnValue({ tags: ['test'] }); - }); - - it('it renders', async () => { - const wrapper = mount( - <MockHookWrapperComponent> - <Tags isLoading={false} /> - </MockHookWrapperComponent> - ); - - await waitFor(() => { - expect(wrapper.find(`[data-test-subj="caseTags"]`).exists()).toBeTruthy(); - }); - }); - - it('it disables the input when loading', async () => { - const wrapper = mount( - <MockHookWrapperComponent> - <Tags isLoading={true} /> - </MockHookWrapperComponent> - ); - - expect(wrapper.find(EuiComboBox).prop('disabled')).toBeTruthy(); - }); - - it('it changes the tags', async () => { - const wrapper = mount( - <MockHookWrapperComponent> - <Tags isLoading={false} /> - </MockHookWrapperComponent> - ); - - await waitFor(() => { - ((wrapper.find(EuiComboBox).props() as unknown) as { - onChange: (a: EuiComboBoxOptionOption[]) => void; - }).onChange(['test', 'case'].map((tag) => ({ label: tag }))); - }); - - expect(globalForm.getFormData()).toEqual({ tags: ['test', 'case'] }); - }); -}); diff --git a/x-pack/plugins/cases/public/components/create/tags.tsx b/x-pack/plugins/cases/public/components/create/tags.tsx deleted file mode 100644 index ac0b67529e15..000000000000 --- a/x-pack/plugins/cases/public/components/create/tags.tsx +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { memo, useMemo } from 'react'; - -import { Field, getUseField } from '../../common/shared_imports'; -import { useGetTags } from '../../containers/use_get_tags'; - -const CommonUseField = getUseField({ component: Field }); - -interface Props { - isLoading: boolean; -} - -const TagsComponent: React.FC<Props> = ({ isLoading }) => { - const { tags: tagOptions, isLoading: isLoadingTags } = useGetTags(); - const options = useMemo( - () => - tagOptions.map((label) => ({ - label, - })), - [tagOptions] - ); - - return ( - <CommonUseField - path="tags" - componentProps={{ - idAria: 'caseTags', - 'data-test-subj': 'caseTags', - euiFieldProps: { - fullWidth: true, - placeholder: '', - disabled: isLoading || isLoadingTags, - options, - noSuggestions: false, - }, - }} - /> - ); -}; - -TagsComponent.displayName = 'TagsComponent'; - -export const Tags = memo(TagsComponent); diff --git a/x-pack/plugins/cases/public/components/create/title.test.tsx b/x-pack/plugins/cases/public/components/create/title.test.tsx deleted file mode 100644 index a41d5afbb403..000000000000 --- a/x-pack/plugins/cases/public/components/create/title.test.tsx +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { mount } from 'enzyme'; -import { act } from '@testing-library/react'; - -import { useForm, Form, FormHook } from '../../common/shared_imports'; -import { Title } from './title'; -import { schema, FormProps } from './schema'; - -describe('Title', () => { - let globalForm: FormHook; - - const MockHookWrapperComponent: React.FC = ({ children }) => { - const { form } = useForm<FormProps>({ - defaultValue: { title: 'My title' }, - schema: { - title: schema.title, - }, - }); - - globalForm = form; - - return <Form form={form}>{children}</Form>; - }; - - beforeEach(() => { - jest.resetAllMocks(); - }); - - it('it renders', async () => { - const wrapper = mount( - <MockHookWrapperComponent> - <Title isLoading={false} /> - </MockHookWrapperComponent> - ); - - expect(wrapper.find(`[data-test-subj="caseTitle"]`).exists()).toBeTruthy(); - }); - - it('it disables the input when loading', async () => { - const wrapper = mount( - <MockHookWrapperComponent> - <Title isLoading={true} /> - </MockHookWrapperComponent> - ); - - expect(wrapper.find(`[data-test-subj="caseTitle"] input`).prop('disabled')).toBeTruthy(); - }); - - it('it changes the title', async () => { - const wrapper = mount( - <MockHookWrapperComponent> - <Title isLoading={false} /> - </MockHookWrapperComponent> - ); - - await act(async () => { - wrapper - .find(`[data-test-subj="caseTitle"] input`) - .first() - .simulate('change', { target: { value: 'My new title' } }); - }); - - expect(globalForm.getFormData()).toEqual({ title: 'My new title' }); - }); -}); diff --git a/x-pack/plugins/cases/public/components/create/title.tsx b/x-pack/plugins/cases/public/components/create/title.tsx deleted file mode 100644 index cc51a805b5c3..000000000000 --- a/x-pack/plugins/cases/public/components/create/title.tsx +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { memo } from 'react'; -import { Field, getUseField } from '../../common/shared_imports'; - -const CommonUseField = getUseField({ component: Field }); - -interface Props { - isLoading: boolean; -} - -const TitleComponent: React.FC<Props> = ({ isLoading }) => ( - <CommonUseField - path="title" - componentProps={{ - idAria: 'caseTitle', - 'data-test-subj': 'caseTitle', - euiFieldProps: { - fullWidth: true, - disabled: isLoading, - }, - }} - /> -); - -TitleComponent.displayName = 'TitleComponent'; - -export const Title = memo(TitleComponent); diff --git a/x-pack/plugins/cases/public/components/create/translations.ts b/x-pack/plugins/cases/public/components/create/translations.ts deleted file mode 100644 index 7e0f7e5a6b9d..000000000000 --- a/x-pack/plugins/cases/public/components/create/translations.ts +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; - -export * from '../../common/translations'; - -export const STEP_ONE_TITLE = i18n.translate('xpack.cases.create.stepOneTitle', { - defaultMessage: 'Case fields', -}); - -export const STEP_TWO_TITLE = i18n.translate('xpack.cases.create.stepTwoTitle', { - defaultMessage: 'Case settings', -}); - -export const STEP_THREE_TITLE = i18n.translate('xpack.cases.create.stepThreeTitle', { - defaultMessage: 'External Connector Fields', -}); - -export const SYNC_ALERTS_LABEL = i18n.translate('xpack.cases.create.syncAlertsLabel', { - defaultMessage: 'Sync alert status with case status', -}); diff --git a/x-pack/plugins/cases/public/components/markdown_editor/editor.tsx b/x-pack/plugins/cases/public/components/markdown_editor/editor.tsx deleted file mode 100644 index a7d37fdda308..000000000000 --- a/x-pack/plugins/cases/public/components/markdown_editor/editor.tsx +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { memo, useEffect, useState, useCallback } from 'react'; -import { - EuiMarkdownEditor, - getDefaultEuiMarkdownParsingPlugins, - getDefaultEuiMarkdownProcessingPlugins, - getDefaultEuiMarkdownUiPlugins, -} from '@elastic/eui'; - -interface MarkdownEditorProps { - onChange: (content: string) => void; - value: string; - ariaLabel: string; - editorId?: string; - dataTestSubj?: string; - height?: number; -} - -// create plugin stuff here -export const { uiPlugins, parsingPlugins, processingPlugins } = { - uiPlugins: getDefaultEuiMarkdownUiPlugins(), - parsingPlugins: getDefaultEuiMarkdownParsingPlugins(), - processingPlugins: getDefaultEuiMarkdownProcessingPlugins(), -}; -const MarkdownEditorComponent: React.FC<MarkdownEditorProps> = ({ - onChange, - value, - ariaLabel, - editorId, - dataTestSubj, - height, -}) => { - const [markdownErrorMessages, setMarkdownErrorMessages] = useState([]); - const onParse = useCallback((err, { messages }) => { - setMarkdownErrorMessages(err ? [err] : messages); - }, []); - - useEffect( - () => document.querySelector<HTMLElement>('textarea.euiMarkdownEditorTextArea')?.focus(), - [] - ); - - return ( - <EuiMarkdownEditor - aria-label={ariaLabel} - editorId={editorId} - onChange={onChange} - value={value} - uiPlugins={uiPlugins} - parsingPluginList={parsingPlugins} - processingPluginList={processingPlugins} - onParse={onParse} - errors={markdownErrorMessages} - data-test-subj={dataTestSubj} - height={height} - /> - ); -}; - -export const MarkdownEditor = memo(MarkdownEditorComponent); diff --git a/x-pack/plugins/cases/public/components/markdown_editor/eui_form.tsx b/x-pack/plugins/cases/public/components/markdown_editor/eui_form.tsx deleted file mode 100644 index 858e79ff65ba..000000000000 --- a/x-pack/plugins/cases/public/components/markdown_editor/eui_form.tsx +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import styled from 'styled-components'; -import { EuiMarkdownEditorProps, EuiFormRow, EuiFlexItem, EuiFlexGroup } from '@elastic/eui'; -import { FieldHook, getFieldValidityAndErrorMessage } from '../../common/shared_imports'; - -import { MarkdownEditor } from './editor'; - -type MarkdownEditorFormProps = EuiMarkdownEditorProps & { - id: string; - field: FieldHook; - dataTestSubj: string; - idAria: string; - isDisabled?: boolean; - bottomRightContent?: React.ReactNode; -}; - -const BottomContentWrapper = styled(EuiFlexGroup)` - ${({ theme }) => ` - padding: ${theme.eui.ruleMargins.marginSmall} 0; - `} -`; - -export const MarkdownEditorForm: React.FC<MarkdownEditorFormProps> = ({ - id, - field, - dataTestSubj, - idAria, - bottomRightContent, -}) => { - const { isInvalid, errorMessage } = getFieldValidityAndErrorMessage(field); - - return ( - <EuiFormRow - data-test-subj={dataTestSubj} - describedByIds={idAria ? [idAria] : undefined} - error={errorMessage} - fullWidth - helpText={field.helpText} - isInvalid={isInvalid} - label={field.label} - labelAppend={field.labelAppend} - > - <> - <MarkdownEditor - ariaLabel={idAria} - editorId={id} - onChange={field.setValue} - value={field.value as string} - data-test-subj={`${dataTestSubj}-markdown-editor`} - /> - {bottomRightContent && ( - <BottomContentWrapper justifyContent={'flexEnd'}> - <EuiFlexItem grow={false}>{bottomRightContent}</EuiFlexItem> - </BottomContentWrapper> - )} - </> - </EuiFormRow> - ); -}; diff --git a/x-pack/plugins/cases/public/components/markdown_editor/index.tsx b/x-pack/plugins/cases/public/components/markdown_editor/index.tsx deleted file mode 100644 index e77a36d48f7d..000000000000 --- a/x-pack/plugins/cases/public/components/markdown_editor/index.tsx +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export * from './types'; -export * from './renderer'; -export * from './editor'; -export * from './eui_form'; diff --git a/x-pack/plugins/cases/public/components/markdown_editor/markdown_link.tsx b/x-pack/plugins/cases/public/components/markdown_editor/markdown_link.tsx deleted file mode 100644 index 7cc8a07c8c04..000000000000 --- a/x-pack/plugins/cases/public/components/markdown_editor/markdown_link.tsx +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { memo } from 'react'; -import { EuiLink, EuiLinkAnchorProps, EuiToolTip } from '@elastic/eui'; - -type MarkdownLinkProps = { disableLinks?: boolean } & EuiLinkAnchorProps; - -/** prevents search engine manipulation by noting the linked document is not trusted or endorsed by us */ -const REL_NOFOLLOW = 'nofollow'; - -const MarkdownLinkComponent: React.FC<MarkdownLinkProps> = ({ - disableLinks, - href, - target, - children, - ...props -}) => ( - <EuiToolTip content={href}> - <EuiLink - href={disableLinks ? undefined : href} - data-test-subj="markdown-link" - rel={`${REL_NOFOLLOW}`} - target="_blank" - > - {children} - </EuiLink> - </EuiToolTip> -); - -export const MarkdownLink = memo(MarkdownLinkComponent); diff --git a/x-pack/plugins/cases/public/components/markdown_editor/renderer.test.tsx b/x-pack/plugins/cases/public/components/markdown_editor/renderer.test.tsx deleted file mode 100644 index 5d299529561b..000000000000 --- a/x-pack/plugins/cases/public/components/markdown_editor/renderer.test.tsx +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { mount } from 'enzyme'; - -import { removeExternalLinkText } from '../../common/test_utils'; -import { MarkdownRenderer } from './renderer'; - -describe('Markdown', () => { - describe('markdown links', () => { - const markdownWithLink = 'A link to an external site [External Site](https://google.com)'; - - test('it renders the expected link text', () => { - const wrapper = mount(<MarkdownRenderer>{markdownWithLink}</MarkdownRenderer>); - - expect( - removeExternalLinkText(wrapper.find('[data-test-subj="markdown-link"]').first().text()) - ).toEqual('External Site'); - }); - - test('it renders the expected href', () => { - const wrapper = mount(<MarkdownRenderer>{markdownWithLink}</MarkdownRenderer>); - - expect(wrapper.find('[data-test-subj="markdown-link"]').first().getDOMNode()).toHaveProperty( - 'href', - 'https://google.com/' - ); - }); - - test('it does NOT render the href if links are disabled', () => { - const wrapper = mount( - <MarkdownRenderer disableLinks={true}>{markdownWithLink}</MarkdownRenderer> - ); - - expect( - wrapper.find('[data-test-subj="markdown-link"]').first().getDOMNode() - ).not.toHaveProperty('href'); - }); - - test('it opens links in a new tab via target="_blank"', () => { - const wrapper = mount(<MarkdownRenderer>{markdownWithLink}</MarkdownRenderer>); - - expect(wrapper.find('[data-test-subj="markdown-link"]').first().getDOMNode()).toHaveProperty( - 'target', - '_blank' - ); - }); - - test('it sets the link `rel` attribute to `noopener` to prevent the new page from accessing `window.opener`, `nofollow` to note the link is not endorsed by us, and noreferrer to prevent the browser from sending the current address', () => { - const wrapper = mount(<MarkdownRenderer>{markdownWithLink}</MarkdownRenderer>); - - expect(wrapper.find('[data-test-subj="markdown-link"]').first().getDOMNode()).toHaveProperty( - 'rel', - 'nofollow noopener noreferrer' - ); - }); - }); -}); diff --git a/x-pack/plugins/cases/public/components/markdown_editor/renderer.tsx b/x-pack/plugins/cases/public/components/markdown_editor/renderer.tsx deleted file mode 100644 index c321c794c1e7..000000000000 --- a/x-pack/plugins/cases/public/components/markdown_editor/renderer.tsx +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { memo, useMemo } from 'react'; -import { cloneDeep } from 'lodash/fp'; -import { EuiMarkdownFormat, EuiLinkAnchorProps } from '@elastic/eui'; - -import { parsingPlugins, processingPlugins } from './'; -import { MarkdownLink } from './markdown_link'; - -interface Props { - children: string; - disableLinks?: boolean; -} - -const MarkdownRendererComponent: React.FC<Props> = ({ children, disableLinks }) => { - const MarkdownLinkProcessingComponent: React.FC<EuiLinkAnchorProps> = useMemo( - () => (props) => <MarkdownLink {...props} disableLinks={disableLinks} />, - [disableLinks] - ); - - // Deep clone of the processing plugins to prevent affecting the markdown editor. - const processingPluginList = cloneDeep(processingPlugins); - // This line of code is TS-compatible and it will break if [1][1] change in the future. - processingPluginList[1][1].components.a = MarkdownLinkProcessingComponent; - - return ( - <EuiMarkdownFormat - parsingPluginList={parsingPlugins} - processingPluginList={processingPluginList} - > - {children} - </EuiMarkdownFormat> - ); -}; - -export const MarkdownRenderer = memo(MarkdownRendererComponent); diff --git a/x-pack/plugins/cases/public/components/markdown_editor/translations.ts b/x-pack/plugins/cases/public/components/markdown_editor/translations.ts deleted file mode 100644 index 365738f53ef8..000000000000 --- a/x-pack/plugins/cases/public/components/markdown_editor/translations.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -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', -}); -export const PREVIEW = i18n.translate('xpack.cases.markdownEditor.preview', { - defaultMessage: 'Preview', -}); diff --git a/x-pack/plugins/cases/public/components/markdown_editor/types.ts b/x-pack/plugins/cases/public/components/markdown_editor/types.ts deleted file mode 100644 index 8a30a4a143f5..000000000000 --- a/x-pack/plugins/cases/public/components/markdown_editor/types.ts +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export interface CursorPosition { - start: number; - end: number; -} diff --git a/x-pack/plugins/cases/public/components/status/button.test.tsx b/x-pack/plugins/cases/public/components/status/button.test.tsx deleted file mode 100644 index a4d4a53ff4a6..000000000000 --- a/x-pack/plugins/cases/public/components/status/button.test.tsx +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { mount } from 'enzyme'; - -import { CaseStatuses } from '../../../common'; -import { StatusActionButton } from './button'; - -describe('StatusActionButton', () => { - const onStatusChanged = jest.fn(); - const defaultProps = { - status: CaseStatuses.open, - disabled: false, - isLoading: false, - onStatusChanged, - }; - - it('it renders', async () => { - const wrapper = mount(<StatusActionButton {...defaultProps} />); - - expect(wrapper.find(`[data-test-subj="case-view-status-action-button"]`).exists()).toBeTruthy(); - }); - - describe('Button icons', () => { - it('it renders the correct button icon: status open', () => { - const wrapper = mount(<StatusActionButton {...defaultProps} />); - - expect( - wrapper.find(`[data-test-subj="case-view-status-action-button"]`).first().prop('iconType') - ).toBe('folderExclamation'); - }); - - it('it renders the correct button icon: status in-progress', () => { - const wrapper = mount( - <StatusActionButton {...defaultProps} status={CaseStatuses['in-progress']} /> - ); - - expect( - wrapper.find(`[data-test-subj="case-view-status-action-button"]`).first().prop('iconType') - ).toBe('folderCheck'); - }); - - it('it renders the correct button icon: status closed', () => { - const wrapper = mount(<StatusActionButton {...defaultProps} status={CaseStatuses.closed} />); - - expect( - wrapper.find(`[data-test-subj="case-view-status-action-button"]`).first().prop('iconType') - ).toBe('folderOpen'); - }); - }); - - describe('Status rotation', () => { - it('rotates correctly to in-progress when status is open', () => { - const wrapper = mount(<StatusActionButton {...defaultProps} />); - - wrapper - .find(`button[data-test-subj="case-view-status-action-button"]`) - .first() - .simulate('click'); - expect(onStatusChanged).toHaveBeenCalledWith('in-progress'); - }); - - it('rotates correctly to closed when status is in-progress', () => { - const wrapper = mount( - <StatusActionButton {...defaultProps} status={CaseStatuses['in-progress']} /> - ); - - wrapper - .find(`button[data-test-subj="case-view-status-action-button"]`) - .first() - .simulate('click'); - expect(onStatusChanged).toHaveBeenCalledWith('closed'); - }); - - it('rotates correctly to open when status is closed', () => { - const wrapper = mount(<StatusActionButton {...defaultProps} status={CaseStatuses.closed} />); - - wrapper - .find(`button[data-test-subj="case-view-status-action-button"]`) - .first() - .simulate('click'); - expect(onStatusChanged).toHaveBeenCalledWith('open'); - }); - }); -}); diff --git a/x-pack/plugins/cases/public/components/status/button.tsx b/x-pack/plugins/cases/public/components/status/button.tsx deleted file mode 100644 index 623afeb43c59..000000000000 --- a/x-pack/plugins/cases/public/components/status/button.tsx +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { memo, useCallback, useMemo } from 'react'; -import { EuiButton } from '@elastic/eui'; - -import { CaseStatuses, caseStatuses } from '../../../common'; -import { statuses } from './config'; - -interface Props { - status: CaseStatuses; - disabled: boolean; - isLoading: boolean; - onStatusChanged: (status: CaseStatuses) => void; -} - -// Rotate over the statuses. open -> in-progress -> closes -> open... -const getNextItem = (item: number) => (item + 1) % caseStatuses.length; - -const StatusActionButtonComponent: React.FC<Props> = ({ - status, - onStatusChanged, - disabled, - isLoading, -}) => { - const indexOfCurrentStatus = useMemo( - () => caseStatuses.findIndex((caseStatus) => caseStatus === status), - [status] - ); - const nextStatusIndex = useMemo(() => getNextItem(indexOfCurrentStatus), [indexOfCurrentStatus]); - - const onClick = useCallback(() => { - onStatusChanged(caseStatuses[nextStatusIndex]); - }, [nextStatusIndex, onStatusChanged]); - - return ( - <EuiButton - data-test-subj="case-view-status-action-button" - iconType={statuses[caseStatuses[nextStatusIndex]].icon} - isDisabled={disabled} - isLoading={isLoading} - onClick={onClick} - > - {statuses[caseStatuses[nextStatusIndex]].button.label} - </EuiButton> - ); -}; -export const StatusActionButton = memo(StatusActionButtonComponent); diff --git a/x-pack/plugins/cases/public/components/status/config.ts b/x-pack/plugins/cases/public/components/status/config.ts deleted file mode 100644 index e85d42906772..000000000000 --- a/x-pack/plugins/cases/public/components/status/config.ts +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import { CaseStatuses } from '../../../common'; -import * as i18n from './translations'; -import { AllCaseStatus, Statuses, StatusAll } from './types'; - -export const allCaseStatus: AllCaseStatus = { - [StatusAll]: { color: 'hollow', label: i18n.ALL }, -}; - -export const statuses: Statuses = { - [CaseStatuses.open]: { - color: 'primary', - label: i18n.OPEN, - icon: 'folderOpen' as const, - actions: { - bulk: { - title: i18n.BULK_ACTION_OPEN_SELECTED, - }, - single: { - title: i18n.OPEN_CASE, - }, - }, - actionBar: { - title: i18n.CASE_OPENED, - }, - button: { - label: i18n.REOPEN_CASE, - }, - stats: { - title: i18n.OPEN_CASES, - }, - }, - [CaseStatuses['in-progress']]: { - color: 'warning', - label: i18n.IN_PROGRESS, - icon: 'folderExclamation' as const, - actions: { - bulk: { - title: i18n.BULK_ACTION_MARK_IN_PROGRESS, - }, - single: { - title: i18n.MARK_CASE_IN_PROGRESS, - }, - }, - actionBar: { - title: i18n.CASE_IN_PROGRESS, - }, - button: { - label: i18n.MARK_CASE_IN_PROGRESS, - }, - stats: { - title: i18n.IN_PROGRESS_CASES, - }, - }, - [CaseStatuses.closed]: { - color: 'default', - label: i18n.CLOSED, - icon: 'folderCheck' as const, - actions: { - bulk: { - title: i18n.BULK_ACTION_CLOSE_SELECTED, - }, - single: { - title: i18n.CLOSE_CASE, - }, - }, - actionBar: { - title: i18n.CASE_CLOSED, - }, - button: { - label: i18n.CLOSE_CASE, - }, - stats: { - title: i18n.CLOSED_CASES, - }, - }, -}; diff --git a/x-pack/plugins/cases/public/components/status/index.ts b/x-pack/plugins/cases/public/components/status/index.ts deleted file mode 100644 index 94d7cb6a3183..000000000000 --- a/x-pack/plugins/cases/public/components/status/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export * from './status'; -export * from './config'; -export * from './stats'; -export * from './types'; diff --git a/x-pack/plugins/cases/public/components/status/stats.test.tsx b/x-pack/plugins/cases/public/components/status/stats.test.tsx deleted file mode 100644 index b2da828da77b..000000000000 --- a/x-pack/plugins/cases/public/components/status/stats.test.tsx +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { mount } from 'enzyme'; - -import { CaseStatuses } from '../../../common'; -import { Stats } from './stats'; - -describe('Stats', () => { - const defaultProps = { - caseStatus: CaseStatuses.open, - caseCount: 2, - isLoading: false, - dataTestSubj: 'test-stats', - }; - it('it renders', async () => { - const wrapper = mount(<Stats {...defaultProps} />); - - expect(wrapper.find(`[data-test-subj="test-stats"]`).exists()).toBeTruthy(); - }); - - it('shows the count', async () => { - const wrapper = mount(<Stats {...defaultProps} />); - - expect( - wrapper.find(`[data-test-subj="test-stats"] .euiDescriptionList__description`).first().text() - ).toBe('2'); - }); - - it('shows the loading spinner', async () => { - const wrapper = mount(<Stats {...defaultProps} isLoading={true} />); - - expect(wrapper.find(`[data-test-subj="test-stats-loading-spinner"]`).exists()).toBeTruthy(); - }); - - describe('Status title', () => { - it('shows the correct title for status open', async () => { - const wrapper = mount(<Stats {...defaultProps} />); - - expect( - wrapper.find(`[data-test-subj="test-stats"] .euiDescriptionList__title`).first().text() - ).toBe('Open cases'); - }); - - it('shows the correct title for status in-progress', async () => { - const wrapper = mount(<Stats {...defaultProps} caseStatus={CaseStatuses['in-progress']} />); - - expect( - wrapper.find(`[data-test-subj="test-stats"] .euiDescriptionList__title`).first().text() - ).toBe('In progress cases'); - }); - - it('shows the correct title for status closed', async () => { - const wrapper = mount(<Stats {...defaultProps} caseStatus={CaseStatuses.closed} />); - - expect( - wrapper.find(`[data-test-subj="test-stats"] .euiDescriptionList__title`).first().text() - ).toBe('Closed cases'); - }); - }); -}); diff --git a/x-pack/plugins/cases/public/components/status/stats.tsx b/x-pack/plugins/cases/public/components/status/stats.tsx deleted file mode 100644 index 071ea43746fd..000000000000 --- a/x-pack/plugins/cases/public/components/status/stats.tsx +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { memo, useMemo } from 'react'; -import { EuiDescriptionList, EuiLoadingSpinner } from '@elastic/eui'; -import { CaseStatuses } from '../../../common'; -import { statuses } from './config'; - -export interface Props { - caseCount: number | null; - caseStatus: CaseStatuses; - isLoading: boolean; - dataTestSubj?: string; -} - -const StatsComponent: React.FC<Props> = ({ caseCount, caseStatus, isLoading, dataTestSubj }) => { - const statusStats = useMemo( - () => [ - { - title: statuses[caseStatus].stats.title, - description: isLoading ? ( - <EuiLoadingSpinner data-test-subj={`${dataTestSubj}-loading-spinner`} /> - ) : ( - caseCount ?? 'N/A' - ), - }, - ], - [caseCount, caseStatus, dataTestSubj, isLoading] - ); - return ( - <EuiDescriptionList data-test-subj={dataTestSubj} textStyle="reverse" listItems={statusStats} /> - ); -}; - -StatsComponent.displayName = 'StatsComponent'; -export const Stats = memo(StatsComponent); diff --git a/x-pack/plugins/cases/public/components/status/status.test.tsx b/x-pack/plugins/cases/public/components/status/status.test.tsx deleted file mode 100644 index 7cddbf5ca4a1..000000000000 --- a/x-pack/plugins/cases/public/components/status/status.test.tsx +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { mount } from 'enzyme'; - -import { CaseStatuses } from '../../../common'; -import { Status } from './status'; - -describe('Stats', () => { - const onClick = jest.fn(); - - it('it renders', async () => { - const wrapper = mount(<Status type={CaseStatuses.open} withArrow={false} onClick={onClick} />); - - expect(wrapper.find(`[data-test-subj="status-badge-open"]`).exists()).toBeTruthy(); - expect( - wrapper.find(`[data-test-subj="status-badge-open"] .euiBadge__iconButton`).exists() - ).toBeFalsy(); - }); - - it('it renders with arrow', async () => { - const wrapper = mount(<Status type={CaseStatuses.open} withArrow={true} onClick={onClick} />); - - expect( - wrapper.find(`[data-test-subj="status-badge-open"] .euiBadge__iconButton`).exists() - ).toBeTruthy(); - }); - - it('it calls onClick when pressing the badge', async () => { - const wrapper = mount(<Status type={CaseStatuses.open} withArrow={true} onClick={onClick} />); - - wrapper.find(`[data-test-subj="status-badge-open"] .euiBadge__iconButton`).simulate('click'); - expect(onClick).toHaveBeenCalled(); - }); - - describe('Colors', () => { - it('shows the correct color when status is open', async () => { - const wrapper = mount( - <Status type={CaseStatuses.open} withArrow={false} onClick={onClick} /> - ); - - expect(wrapper.find(`[data-test-subj="status-badge-open"]`).first().prop('color')).toBe( - 'primary' - ); - }); - - it('shows the correct color when status is in-progress', async () => { - const wrapper = mount( - <Status type={CaseStatuses['in-progress']} withArrow={false} onClick={onClick} /> - ); - - expect( - wrapper.find(`[data-test-subj="status-badge-in-progress"]`).first().prop('color') - ).toBe('warning'); - }); - - it('shows the correct color when status is closed', async () => { - const wrapper = mount( - <Status type={CaseStatuses.closed} withArrow={false} onClick={onClick} /> - ); - - expect(wrapper.find(`[data-test-subj="status-badge-closed"]`).first().prop('color')).toBe( - 'default' - ); - }); - }); -}); diff --git a/x-pack/plugins/cases/public/components/status/status.tsx b/x-pack/plugins/cases/public/components/status/status.tsx deleted file mode 100644 index de4c979daf4c..000000000000 --- a/x-pack/plugins/cases/public/components/status/status.tsx +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { memo, useMemo } from 'react'; -import { noop } from 'lodash/fp'; -import { EuiBadge } from '@elastic/eui'; - -import { allCaseStatus, statuses } from './config'; -import { CaseStatusWithAllStatus, StatusAll } from './types'; -import * as i18n from './translations'; - -interface Props { - type: CaseStatusWithAllStatus; - withArrow?: boolean; - onClick?: () => void; -} - -const StatusComponent: React.FC<Props> = ({ type, withArrow = false, onClick = noop }) => { - const props = useMemo( - () => ({ - color: type === StatusAll ? allCaseStatus[StatusAll].color : statuses[type].color, - ...(withArrow ? { iconType: 'arrowDown', iconSide: 'right' as const } : {}), - }), - [withArrow, type] - ); - - return ( - <EuiBadge - {...props} - iconOnClick={onClick} - iconOnClickAriaLabel={i18n.STATUS_ICON_ARIA} - data-test-subj={`status-badge-${type}`} - > - {type === StatusAll ? allCaseStatus[StatusAll].label : statuses[type].label} - </EuiBadge> - ); -}; - -export const Status = memo(StatusComponent); diff --git a/x-pack/plugins/cases/public/components/status/translations.ts b/x-pack/plugins/cases/public/components/status/translations.ts deleted file mode 100644 index b3eadfd681ba..000000000000 --- a/x-pack/plugins/cases/public/components/status/translations.ts +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; -export * from '../../common/translations'; - -export const ALL = i18n.translate('xpack.cases.status.all', { - defaultMessage: 'All', -}); - -export const OPEN = i18n.translate('xpack.cases.status.open', { - defaultMessage: 'Open', -}); - -export const IN_PROGRESS = i18n.translate('xpack.cases.status.inProgress', { - defaultMessage: 'In progress', -}); - -export const CLOSED = i18n.translate('xpack.cases.status.closed', { - defaultMessage: 'Closed', -}); - -export const STATUS_ICON_ARIA = i18n.translate('xpack.cases.status.iconAria', { - defaultMessage: 'Change status', -}); - -export const CASE_OPENED = i18n.translate('xpack.cases.caseView.caseOpened', { - defaultMessage: 'Case opened', -}); - -export const CASE_IN_PROGRESS = i18n.translate('xpack.cases.caseView.caseInProgress', { - defaultMessage: 'Case in progress', -}); - -export const CASE_CLOSED = i18n.translate('xpack.cases.caseView.caseClosed', { - defaultMessage: 'Case closed', -}); - -export const BULK_ACTION_CLOSE_SELECTED = i18n.translate( - 'xpack.cases.caseTable.bulkActions.closeSelectedTitle', - { - defaultMessage: 'Close selected', - } -); - -export const BULK_ACTION_OPEN_SELECTED = i18n.translate( - 'xpack.cases.caseTable.bulkActions.openSelectedTitle', - { - defaultMessage: 'Open selected', - } -); - -export const BULK_ACTION_DELETE_SELECTED = i18n.translate( - 'xpack.cases.caseTable.bulkActions.deleteSelectedTitle', - { - defaultMessage: 'Delete selected', - } -); - -export const BULK_ACTION_MARK_IN_PROGRESS = i18n.translate( - 'xpack.cases.caseTable.bulkActions.markInProgressTitle', - { - defaultMessage: 'Mark in progress', - } -); diff --git a/x-pack/plugins/cases/public/components/status/types.ts b/x-pack/plugins/cases/public/components/status/types.ts deleted file mode 100644 index 674838067b0a..000000000000 --- a/x-pack/plugins/cases/public/components/status/types.ts +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiIconType } from '@elastic/eui/src/components/icon/icon'; -import { CaseStatuses } from '../../../common'; - -export const StatusAll = 'all' as const; -type StatusAllType = typeof StatusAll; - -export type CaseStatusWithAllStatus = CaseStatuses | StatusAllType; - -export type AllCaseStatus = Record<StatusAllType, { color: string; label: string }>; - -export type Statuses = Record< - CaseStatuses, - { - color: string; - label: string; - icon: EuiIconType; - actions: { - bulk: { - title: string; - }; - single: { - title: string; - description?: string; - }; - }; - actionBar: { - title: string; - }; - button: { - label: string; - }; - stats: { - title: string; - }; - } ->; diff --git a/x-pack/plugins/cases/public/components/toasters/__snapshots__/modal_all_errors.test.tsx.snap b/x-pack/plugins/cases/public/components/toasters/__snapshots__/modal_all_errors.test.tsx.snap deleted file mode 100644 index 5e008e28073d..000000000000 --- a/x-pack/plugins/cases/public/components/toasters/__snapshots__/modal_all_errors.test.tsx.snap +++ /dev/null @@ -1,48 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Modal all errors rendering it renders the default all errors modal when isShowing is positive 1`] = ` -<EuiModal - onClose={[Function]} -> - <EuiModalHeader> - <EuiModalHeaderTitle> - Your visualization has error(s) - </EuiModalHeaderTitle> - </EuiModalHeader> - <EuiModalBody> - <EuiCallOut - color="danger" - iconType="alert" - size="s" - title="Test & Test" - /> - <EuiSpacer - size="s" - /> - <EuiAccordion - arrowDisplay="left" - buttonContent="Error 1, Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt u ..." - data-test-subj="modal-all-errors-accordion" - id="accordion1" - initialIsOpen={true} - isLoading={false} - isLoadingMessage={false} - key="id-super-id-0" - paddingSize="none" - > - <MyEuiCodeBlock> - Error 1, Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. - </MyEuiCodeBlock> - </EuiAccordion> - </EuiModalBody> - <EuiModalFooter> - <EuiButton - data-test-subj="modal-all-errors-close" - fill={true} - onClick={[Function]} - > - Close - </EuiButton> - </EuiModalFooter> -</EuiModal> -`; diff --git a/x-pack/plugins/cases/public/components/toasters/errors.ts b/x-pack/plugins/cases/public/components/toasters/errors.ts deleted file mode 100644 index 0a672aeee8b7..000000000000 --- a/x-pack/plugins/cases/public/components/toasters/errors.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export class ToasterError extends Error { - public readonly messages: string[]; - - constructor(messages: string[]) { - super(messages[0]); - this.name = 'ToasterError'; - this.messages = messages; - } -} - -export const isToasterError = (error: unknown): error is ToasterError => - error instanceof ToasterError; diff --git a/x-pack/plugins/cases/public/components/toasters/index.test.tsx b/x-pack/plugins/cases/public/components/toasters/index.test.tsx deleted file mode 100644 index 1d78570e18a5..000000000000 --- a/x-pack/plugins/cases/public/components/toasters/index.test.tsx +++ /dev/null @@ -1,307 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { set } from '@elastic/safer-lodash-set/fp'; -import { cloneDeep } from 'lodash/fp'; -import { mount } from 'enzyme'; -import React, { useEffect } from 'react'; - -import { - AppToast, - useStateToaster, - ManageGlobalToaster, - GlobalToaster, - displayErrorToast, -} from '.'; - -jest.mock('uuid', () => { - return { - v1: jest.fn(() => '27261ae0-0bbb-11ea-b0ea-db767b07ea47'), - v4: jest.fn(() => '9e1f72a9-7c73-4b7f-a562-09940f7daf4a'), - }; -}); - -const mockToast: AppToast = { - color: 'danger', - id: 'id-super-id', - iconType: 'alert', - title: 'Test & Test', - toastLifeTimeMs: 100, - text: - 'Error 1, Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', -}; - -describe('Toaster', () => { - describe('Manage Global Toaster Reducer', () => { - test('we can add a toast in the reducer', () => { - const AddToaster = () => { - const [{ toasts }, dispatch] = useStateToaster(); - return ( - <> - <button - data-test-subj="add-toast" - type="button" - onClick={() => dispatch({ type: 'addToaster', toast: mockToast })} - /> - {toasts.map((toast) => ( - <span - data-test-subj={`add-toaster-${toast.id}`} - key={`add-toaster-${toast.id}`} - >{`${toast.title} ${toast.text}`}</span> - ))} - </> - ); - }; - const wrapper = mount( - <ManageGlobalToaster> - <AddToaster /> - </ManageGlobalToaster> - ); - wrapper.find('[data-test-subj="add-toast"]').simulate('click'); - expect(wrapper.find('[data-test-subj="add-toaster-id-super-id"]').exists()).toBe(true); - }); - test('we can delete a toast in the reducer', () => { - const DeleteToaster = () => { - const [{ toasts }, dispatch] = useStateToaster(); - useEffect(() => { - if (toasts.length === 0) { - dispatch({ type: 'addToaster', toast: mockToast }); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - return ( - <> - <button - data-test-subj="delete-toast" - type="button" - onClick={() => dispatch({ type: 'deleteToaster', id: mockToast.id })} - /> - {toasts.map((toast) => ( - <span - data-test-subj={`delete-toaster-${toast.id}`} - key={`delete-toaster-${toast.id}`} - >{`${toast.title} ${toast.text}`}</span> - ))} - </> - ); - }; - const wrapper = mount( - <ManageGlobalToaster> - <DeleteToaster /> - </ManageGlobalToaster> - ); - - expect(wrapper.find('[data-test-subj="delete-toaster-id-super-id"]').exists()).toBe(true); - wrapper.find('[data-test-subj="delete-toast"]').simulate('click'); - expect(wrapper.find('[data-test-subj="delete-toaster-id-super-id"]').exists()).toBe(false); - }); - }); - - describe('Global Toaster', () => { - test('Render a basic toaster', () => { - const AddToaster = () => { - const [{ toasts }, dispatch] = useStateToaster(); - return ( - <> - <button - data-test-subj="add-toast" - type="button" - onClick={() => dispatch({ type: 'addToaster', toast: mockToast })} - /> - {toasts.map((toast) => ( - <span key={`add-toaster-${toast.id}`}>{`${toast.title} ${toast.text}`}</span> - ))} - </> - ); - }; - const wrapper = mount( - <ManageGlobalToaster> - <AddToaster /> - <GlobalToaster /> - </ManageGlobalToaster> - ); - wrapper.find('[data-test-subj="add-toast"]').simulate('click'); - - expect(wrapper.find('.euiGlobalToastList').exists()).toBe(true); - expect(wrapper.find('.euiToastHeader__title').text()).toBe('Test & Test'); - }); - - test('Render an error toaster', () => { - let mockErrorToast: AppToast = cloneDeep(mockToast); - mockErrorToast.title = 'Test & Test ERROR'; - mockErrorToast = set('errors', [mockErrorToast.text], mockErrorToast); - - const AddToaster = () => { - const [{ toasts }, dispatch] = useStateToaster(); - return ( - <> - <button - data-test-subj="add-toast" - type="button" - onClick={() => dispatch({ type: 'addToaster', toast: mockErrorToast })} - /> - {toasts.map((toast) => ( - <span key={`add-toaster-${toast.id}`}>{`${toast.title} ${toast.text}`}</span> - ))} - </> - ); - }; - const wrapper = mount( - <ManageGlobalToaster> - <AddToaster /> - <GlobalToaster /> - </ManageGlobalToaster> - ); - wrapper.find('[data-test-subj="add-toast"]').simulate('click'); - - expect(wrapper.find('.euiGlobalToastList').exists()).toBe(true); - expect(wrapper.find('.euiToastHeader__title').text()).toBe('Test & Test ERROR'); - expect(wrapper.find('button[data-test-subj="toaster-show-all-error-modal"]').exists()).toBe( - true - ); - }); - - test('Only show one toast at the time', () => { - const mockOneMoreToast: AppToast = cloneDeep(mockToast); - mockOneMoreToast.id = 'id-super-id-II'; - mockOneMoreToast.title = 'Test & Test II'; - - const AddToaster = () => { - const [{ toasts }, dispatch] = useStateToaster(); - return ( - <> - <button - data-test-subj="add-toast" - type="button" - onClick={() => { - dispatch({ type: 'addToaster', toast: mockToast }); - dispatch({ type: 'addToaster', toast: mockOneMoreToast }); - }} - /> - <button - data-test-subj="delete-toast" - type="button" - onClick={() => { - dispatch({ type: 'deleteToaster', id: mockToast.id }); - }} - /> - {toasts.map((toast) => ( - <span key={`add-toaster-${toast.id}`}>{`${toast.title} ${toast.text}`}</span> - ))} - </> - ); - }; - const wrapper = mount( - <ManageGlobalToaster> - <AddToaster /> - <GlobalToaster /> - </ManageGlobalToaster> - ); - wrapper.find('[data-test-subj="add-toast"]').simulate('click'); - - expect(wrapper.find('button[data-test-subj="toastCloseButton"]').length).toBe(1); - expect(wrapper.find('.euiToastHeader__title').text()).toBe('Test & Test'); - wrapper.find('button[data-test-subj="delete-toast"]').simulate('click'); - expect(wrapper.find('.euiToast').length).toBe(1); - expect(wrapper.find('.euiToastHeader__title').text()).toBe('Test & Test II'); - }); - - test('Do not show anymore toaster when modal error is open', () => { - let mockErrorToast: AppToast = cloneDeep(mockToast); - mockErrorToast.id = 'id-super-id-error'; - mockErrorToast = set('errors', [mockErrorToast.text], mockErrorToast); - - const AddToaster = () => { - const [{ toasts }, dispatch] = useStateToaster(); - return ( - <> - <button - data-test-subj="add-toast" - type="button" - onClick={() => { - dispatch({ type: 'addToaster', toast: mockErrorToast }); - dispatch({ type: 'addToaster', toast: mockToast }); - }} - /> - {toasts.map((toast) => ( - <span key={`add-toaster-${toast.id}`}>{`${toast.title} ${toast.text}`}</span> - ))} - </> - ); - }; - const wrapper = mount( - <ManageGlobalToaster> - <AddToaster /> - <GlobalToaster /> - </ManageGlobalToaster> - ); - wrapper.find('[data-test-subj="add-toast"]').simulate('click'); - wrapper.find('button[data-test-subj="toaster-show-all-error-modal"]').simulate('click'); - - expect(wrapper.find('.euiToast').length).toBe(0); - }); - - test('Show new toaster when modal error is closing', () => { - let mockErrorToast: AppToast = cloneDeep(mockToast); - mockErrorToast.title = 'Test & Test II'; - mockErrorToast.id = 'id-super-id-error'; - mockErrorToast = set('errors', [mockErrorToast.text], mockErrorToast); - - const AddToaster = () => { - const [{ toasts }, dispatch] = useStateToaster(); - return ( - <> - <button - data-test-subj="add-toast" - type="button" - onClick={() => { - dispatch({ type: 'addToaster', toast: mockErrorToast }); - dispatch({ type: 'addToaster', toast: mockToast }); - }} - /> - {toasts.map((toast) => ( - <span key={`add-toaster-${toast.id}`}>{`${toast.title} ${toast.text}`}</span> - ))} - </> - ); - }; - const wrapper = mount( - <ManageGlobalToaster> - <AddToaster /> - <GlobalToaster /> - </ManageGlobalToaster> - ); - wrapper.find('[data-test-subj="add-toast"]').simulate('click'); - expect(wrapper.find('.euiToastHeader__title').text()).toBe('Test & Test II'); - - wrapper.find('button[data-test-subj="toaster-show-all-error-modal"]').simulate('click'); - expect(wrapper.find('.euiToast').length).toBe(0); - - wrapper.find('button[data-test-subj="modal-all-errors-close"]').simulate('click'); - expect(wrapper.find('.euiToast').length).toBe(1); - expect(wrapper.find('.euiToastHeader__title').text()).toBe('Test & Test'); - }); - }); - - describe('displayErrorToast', () => { - test('dispatches toast with correct title and message', () => { - const mockErrorToast = { - toast: { - color: 'danger', - errors: ['message'], - iconType: 'alert', - id: '9e1f72a9-7c73-4b7f-a562-09940f7daf4a', - title: 'Title', - }, - type: 'addToaster', - }; - const dispatchToasterMock = jest.fn(); - displayErrorToast('Title', ['message'], dispatchToasterMock); - expect(dispatchToasterMock.mock.calls[0][0]).toEqual(mockErrorToast); - }); - }); -}); diff --git a/x-pack/plugins/cases/public/components/toasters/index.tsx b/x-pack/plugins/cases/public/components/toasters/index.tsx deleted file mode 100644 index ea17b0308275..000000000000 --- a/x-pack/plugins/cases/public/components/toasters/index.tsx +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiButton, EuiGlobalToastList, EuiGlobalToastListToast as Toast } from '@elastic/eui'; -import { noop } from 'lodash/fp'; -import React, { createContext, Dispatch, useContext, useReducer, useState } from 'react'; -import styled from 'styled-components'; - -import { ModalAllErrors } from './modal_all_errors'; -import * as i18n from './translations'; - -export * from './utils'; -export * from './errors'; - -export interface AppToast extends Toast { - errors?: string[]; -} - -interface ToastState { - toasts: AppToast[]; -} - -const initialToasterState: ToastState = { - toasts: [], -}; - -export type ActionToaster = - | { type: 'addToaster'; toast: AppToast } - | { type: 'deleteToaster'; id: string } - | { type: 'toggleWaitToShowNextToast' }; - -export const StateToasterContext = createContext<[ToastState, Dispatch<ActionToaster>]>([ - initialToasterState, - () => noop, -]); - -export const useStateToaster = () => useContext(StateToasterContext); - -interface ManageGlobalToasterProps { - children: React.ReactNode; -} - -export const ManageGlobalToaster = ({ children }: ManageGlobalToasterProps) => { - const reducerToaster = (state: ToastState, action: ActionToaster) => { - switch (action.type) { - case 'addToaster': - return { ...state, toasts: [...state.toasts, action.toast] }; - case 'deleteToaster': - return { ...state, toasts: state.toasts.filter((msg) => msg.id !== action.id) }; - default: - return state; - } - }; - - return ( - <StateToasterContext.Provider value={useReducer(reducerToaster, initialToasterState)}> - {children} - </StateToasterContext.Provider> - ); -}; - -const GlobalToasterListContainer = styled.div` - position: absolute; - right: 0; - bottom: 0; -`; - -interface GlobalToasterProps { - toastLifeTimeMs?: number; -} - -export const GlobalToaster = ({ toastLifeTimeMs = 5000 }: GlobalToasterProps) => { - const [{ toasts }, dispatch] = useStateToaster(); - const [isShowing, setIsShowing] = useState(false); - const [toastInModal, setToastInModal] = useState<AppToast | null>(null); - - const toggle = (toast: AppToast) => { - if (isShowing) { - dispatch({ type: 'deleteToaster', id: toast.id }); - setToastInModal(null); - } else { - setToastInModal(toast); - } - setIsShowing(!isShowing); - }; - - return ( - <> - {toasts.length > 0 && !isShowing && ( - <GlobalToasterListContainer> - <EuiGlobalToastList - toasts={[formatToErrorToastIfNeeded(toasts[0], toggle)]} - dismissToast={({ id }) => { - dispatch({ type: 'deleteToaster', id }); - }} - toastLifeTimeMs={toastLifeTimeMs} - /> - </GlobalToasterListContainer> - )} - {toastInModal != null && ( - <ModalAllErrors isShowing={isShowing} toast={toastInModal} toggle={toggle} /> - )} - </> - ); -}; - -const formatToErrorToastIfNeeded = ( - toast: AppToast, - toggle: (toast: AppToast) => void -): AppToast => { - if (toast != null && toast.errors != null && toast.errors.length > 0) { - toast.text = ( - <ErrorToastContainer> - <EuiButton - data-test-subj="toaster-show-all-error-modal" - size="s" - color="danger" - onClick={() => toast != null && toggle(toast)} - > - {i18n.SEE_ALL_ERRORS} - </EuiButton> - </ErrorToastContainer> - ); - } - return toast; -}; - -const ErrorToastContainer = styled.div` - text-align: right; -`; - -ErrorToastContainer.displayName = 'ErrorToastContainer'; diff --git a/x-pack/plugins/cases/public/components/toasters/modal_all_errors.test.tsx b/x-pack/plugins/cases/public/components/toasters/modal_all_errors.test.tsx deleted file mode 100644 index 7ec055359110..000000000000 --- a/x-pack/plugins/cases/public/components/toasters/modal_all_errors.test.tsx +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { shallow } from 'enzyme'; - -import React from 'react'; - -import { ModalAllErrors } from './modal_all_errors'; -import { AppToast } from '.'; -import { cloneDeep } from 'lodash/fp'; - -const mockToast: AppToast = { - color: 'danger', - id: 'id-super-id', - iconType: 'alert', - title: 'Test & Test', - errors: [ - 'Error 1, Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', - ], -}; - -describe('Modal all errors', () => { - const toggle = jest.fn(); - describe('rendering', () => { - test('it renders the default all errors modal when isShowing is positive', () => { - const wrapper = shallow( - <ModalAllErrors isShowing={true} toast={mockToast} toggle={toggle} /> - ); - expect(wrapper).toMatchSnapshot(); - }); - - test('it renders null when isShowing is negative', () => { - const wrapper = shallow( - <ModalAllErrors isShowing={false} toast={mockToast} toggle={toggle} /> - ); - expect(wrapper.html()).toEqual(null); - }); - - test('it renders multiple errors in modal', () => { - const mockToastWithTwoError = cloneDeep(mockToast); - mockToastWithTwoError.errors = [ - 'Error 1, Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', - 'Error 2, Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', - 'Error 3, Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', - ]; - const wrapper = shallow( - <ModalAllErrors isShowing={true} toast={mockToastWithTwoError} toggle={toggle} /> - ); - expect(wrapper.find('[data-test-subj="modal-all-errors-accordion"]').length).toBe( - mockToastWithTwoError.errors.length - ); - }); - }); - - describe('events', () => { - test('Make sure that toggle function has been called when you click on the close button', () => { - const wrapper = shallow( - <ModalAllErrors isShowing={true} toast={mockToast} toggle={toggle} /> - ); - - wrapper.find('[data-test-subj="modal-all-errors-close"]').simulate('click'); - wrapper.update(); - expect(toggle).toHaveBeenCalledWith(mockToast); - }); - }); -}); diff --git a/x-pack/plugins/cases/public/components/toasters/modal_all_errors.tsx b/x-pack/plugins/cases/public/components/toasters/modal_all_errors.tsx deleted file mode 100644 index 0a78139f5fe3..000000000000 --- a/x-pack/plugins/cases/public/components/toasters/modal_all_errors.tsx +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - EuiButton, - EuiModal, - EuiModalHeader, - EuiModalHeaderTitle, - EuiModalBody, - EuiCallOut, - EuiSpacer, - EuiCodeBlock, - EuiModalFooter, - EuiAccordion, -} from '@elastic/eui'; -import React, { useCallback } from 'react'; -import styled from 'styled-components'; - -import { AppToast } from '.'; -import * as i18n from './translations'; - -interface FullErrorProps { - isShowing: boolean; - toast: AppToast; - toggle: (toast: AppToast) => void; -} - -const ModalAllErrorsComponent: React.FC<FullErrorProps> = ({ isShowing, toast, toggle }) => { - const handleClose = useCallback(() => toggle(toast), [toggle, toast]); - - if (!isShowing || toast == null) return null; - - return ( - <EuiModal onClose={handleClose}> - <EuiModalHeader> - <EuiModalHeaderTitle>{i18n.TITLE_ERROR_MODAL}</EuiModalHeaderTitle> - </EuiModalHeader> - - <EuiModalBody> - <EuiCallOut title={toast.title} color="danger" size="s" iconType="alert" /> - <EuiSpacer size="s" /> - {toast.errors != null && - toast.errors.map((error, index) => ( - <EuiAccordion - key={`${toast.id}-${index}`} - id="accordion1" - initialIsOpen={index === 0 ? true : false} - buttonContent={error.length > 100 ? `${error.substring(0, 100)} ...` : error} - data-test-subj="modal-all-errors-accordion" - > - <MyEuiCodeBlock>{error}</MyEuiCodeBlock> - </EuiAccordion> - ))} - </EuiModalBody> - - <EuiModalFooter> - <EuiButton onClick={handleClose} fill data-test-subj="modal-all-errors-close"> - {i18n.CLOSE_ERROR_MODAL} - </EuiButton> - </EuiModalFooter> - </EuiModal> - ); -}; - -export const ModalAllErrors = React.memo(ModalAllErrorsComponent); - -const MyEuiCodeBlock = styled(EuiCodeBlock)` - margin-top: 4px; -`; - -MyEuiCodeBlock.displayName = 'MyEuiCodeBlock'; diff --git a/x-pack/plugins/cases/public/components/toasters/translations.ts b/x-pack/plugins/cases/public/components/toasters/translations.ts deleted file mode 100644 index cf7fac462a12..000000000000 --- a/x-pack/plugins/cases/public/components/toasters/translations.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; - -export const SEE_ALL_ERRORS = i18n.translate('xpack.cases.modalAllErrors.seeAllErrors.button', { - defaultMessage: 'See the full error(s)', -}); - -export const TITLE_ERROR_MODAL = i18n.translate('xpack.cases.modalAllErrors.title', { - defaultMessage: 'Your visualization has error(s)', -}); - -export const CLOSE_ERROR_MODAL = i18n.translate('xpack.cases.modalAllErrors.close.button', { - defaultMessage: 'Close', -}); diff --git a/x-pack/plugins/cases/public/components/toasters/utils.test.ts b/x-pack/plugins/cases/public/components/toasters/utils.test.ts deleted file mode 100644 index 34871b2e68ef..000000000000 --- a/x-pack/plugins/cases/public/components/toasters/utils.test.ts +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { errorToToaster } from './utils'; -import { ToasterError } from './errors'; - -const ApiError = class extends Error { - public body: {} = {}; -}; - -describe('error_to_toaster', () => { - let dispatchToaster = jest.fn(); - - beforeEach(() => { - dispatchToaster = jest.fn(); - }); - - describe('#errorToToaster', () => { - test('dispatches an error toast given a ToasterError with multiple error messages', () => { - const error = new ToasterError(['some error 1', 'some error 2']); - errorToToaster({ id: 'some-made-up-id', title: 'some title', error, dispatchToaster }); - expect(dispatchToaster.mock.calls[0]).toEqual([ - { - toast: { - color: 'danger', - errors: ['some error 1', 'some error 2'], - iconType: 'alert', - id: 'some-made-up-id', - title: 'some title', - }, - type: 'addToaster', - }, - ]); - }); - - test('dispatches an error toast given a ToasterError with a single error message', () => { - const error = new ToasterError(['some error 1']); - errorToToaster({ id: 'some-made-up-id', title: 'some title', error, dispatchToaster }); - expect(dispatchToaster.mock.calls[0]).toEqual([ - { - toast: { - color: 'danger', - errors: ['some error 1'], - iconType: 'alert', - id: 'some-made-up-id', - title: 'some title', - }, - type: 'addToaster', - }, - ]); - }); - - test('dispatches an error toast given an ApiError with a message', () => { - const error = new ApiError('Internal Server Error'); - error.body = { message: 'something bad happened', status_code: 500 }; - - errorToToaster({ id: 'some-made-up-id', title: 'some title', error, dispatchToaster }); - expect(dispatchToaster.mock.calls[0]).toEqual([ - { - toast: { - color: 'danger', - errors: ['something bad happened'], - iconType: 'alert', - id: 'some-made-up-id', - title: 'some title', - }, - type: 'addToaster', - }, - ]); - }); - - test('dispatches an error toast given an ApiError with no message', () => { - const error = new ApiError('Internal Server Error'); - - errorToToaster({ id: 'some-made-up-id', title: 'some title', error, dispatchToaster }); - expect(dispatchToaster.mock.calls[0]).toEqual([ - { - toast: { - color: 'danger', - errors: ['Internal Server Error'], - iconType: 'alert', - id: 'some-made-up-id', - title: 'some title', - }, - type: 'addToaster', - }, - ]); - }); - - test('dispatches an error toast given a standard Error', () => { - const error = new Error('some error 1'); - errorToToaster({ id: 'some-made-up-id', title: 'some title', error, dispatchToaster }); - expect(dispatchToaster.mock.calls[0]).toEqual([ - { - toast: { - color: 'danger', - errors: ['some error 1'], - iconType: 'alert', - id: 'some-made-up-id', - title: 'some title', - }, - type: 'addToaster', - }, - ]); - }); - - test('adds a generic Network Error given a non Error object such as a string', () => { - const error = 'terrible string'; - errorToToaster({ id: 'some-made-up-id', title: 'some title', error, dispatchToaster }); - expect(dispatchToaster.mock.calls[0]).toEqual([ - { - toast: { - color: 'danger', - errors: ['Network Error'], - iconType: 'alert', - id: 'some-made-up-id', - title: 'some title', - }, - type: 'addToaster', - }, - ]); - }); - }); -}); diff --git a/x-pack/plugins/cases/public/components/toasters/utils.ts b/x-pack/plugins/cases/public/components/toasters/utils.ts deleted file mode 100644 index 0575c4010766..000000000000 --- a/x-pack/plugins/cases/public/components/toasters/utils.ts +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type React from 'react'; -import uuid from 'uuid'; -import { isError } from 'lodash/fp'; - -import { AppToast, ActionToaster } from './'; -import { isToasterError } from './errors'; -import { isAppError } from '../../common/errors'; - -/** - * Displays an error toast for the provided title and message - * - * @param errorTitle Title of error to display in toaster and modal - * @param errorMessages Message to display in error modal when clicked - * @param dispatchToaster provided by useStateToaster() - */ -export const displayErrorToast = ( - errorTitle: string, - errorMessages: string[], - dispatchToaster: React.Dispatch<ActionToaster>, - id: string = uuid.v4() -): void => { - const toast: AppToast = { - id, - title: errorTitle, - color: 'danger', - iconType: 'alert', - errors: errorMessages, - }; - dispatchToaster({ - type: 'addToaster', - toast, - }); -}; - -/** - * Displays a warning toast for the provided title and message - * - * @param title warning message to display in toaster and modal - * @param dispatchToaster provided by useStateToaster() - * @param id unique ID if necessary - */ -export const displayWarningToast = ( - title: string, - dispatchToaster: React.Dispatch<ActionToaster>, - id: string = uuid.v4() -): void => { - const toast: AppToast = { - id, - title, - color: 'warning', - iconType: 'help', - }; - dispatchToaster({ - type: 'addToaster', - toast, - }); -}; - -/** - * Displays a success toast for the provided title and message - * - * @param title success message to display in toaster and modal - * @param dispatchToaster provided by useStateToaster() - */ -export const displaySuccessToast = ( - title: string, - dispatchToaster: React.Dispatch<ActionToaster>, - id: string = uuid.v4() -): void => { - const toast: AppToast = { - id, - title, - color: 'success', - iconType: 'check', - }; - dispatchToaster({ - type: 'addToaster', - toast, - }); -}; - -export type ErrorToToasterArgs = Partial<AppToast> & { - error: unknown; - dispatchToaster: React.Dispatch<ActionToaster>; -}; - -/** - * Displays an error toast with messages parsed from the error - * - * @param title error message to display in toaster and modal - * @param error the error from which messages will be parsed - * @param dispatchToaster provided by useStateToaster() - */ -export const errorToToaster = ({ - id = uuid.v4(), - title, - error, - color = 'danger', - iconType = 'alert', - dispatchToaster, -}: ErrorToToasterArgs) => { - let toast: AppToast; - - if (isToasterError(error)) { - toast = { - id, - title, - color, - iconType, - errors: error.messages, - }; - } else if (isAppError(error)) { - toast = { - id, - title, - color, - iconType, - errors: [error.body.message], - }; - } else if (isError(error)) { - toast = { - id, - title, - color, - iconType, - errors: [error.message], - }; - } else { - toast = { - id, - title, - color, - iconType, - errors: ['Network Error'], - }; - } - - dispatchToaster({ - type: 'addToaster', - toast, - }); -}; diff --git a/x-pack/plugins/cases/public/components/use_create_case_modal/create_case_modal.test.tsx b/x-pack/plugins/cases/public/components/use_create_case_modal/create_case_modal.test.tsx deleted file mode 100644 index fcdc2f8e5877..000000000000 --- a/x-pack/plugins/cases/public/components/use_create_case_modal/create_case_modal.test.tsx +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { ReactNode } from 'react'; -import { mount } from 'enzyme'; - -import { CreateCaseModal } from './create_case_modal'; -import { TestProviders } from '../../common/mock'; - -jest.mock('../create/form_context', () => { - return { - FormContext: ({ - children, - onSuccess, - }: { - children: ReactNode; - onSuccess: ({ id }: { id: string }) => Promise<void>; - }) => { - return ( - <> - <button - type="button" - data-test-subj="form-context-on-success" - onClick={async () => { - await onSuccess({ id: 'case-id' }); - }} - > - {'submit'} - </button> - {children} - </> - ); - }, - }; -}); - -jest.mock('../create/form', () => { - return { - CreateCaseForm: () => { - return <>{'form'}</>; - }, - }; -}); - -jest.mock('../create/submit_button', () => { - return { - SubmitCaseButton: () => { - return <>{'Submit'}</>; - }, - }; -}); - -const onCloseCaseModal = jest.fn(); -const onSuccess = jest.fn(); -const defaultProps = { - isModalOpen: true, - onCloseCaseModal, - onSuccess, -}; - -describe('CreateCaseModal', () => { - beforeEach(() => { - jest.resetAllMocks(); - }); - - it('renders', () => { - const wrapper = mount( - <TestProviders> - <CreateCaseModal {...defaultProps} /> - </TestProviders> - ); - - expect(wrapper.find(`[data-test-subj='all-cases-modal']`).exists()).toBeTruthy(); - }); - - it('it does not render the modal isModalOpen=false ', () => { - const wrapper = mount( - <TestProviders> - <CreateCaseModal {...defaultProps} isModalOpen={false} /> - </TestProviders> - ); - - expect(wrapper.find(`[data-test-subj='all-cases-modal']`).exists()).toBeFalsy(); - }); - - it('Closing modal calls onCloseCaseModal', () => { - const wrapper = mount( - <TestProviders> - <CreateCaseModal {...defaultProps} /> - </TestProviders> - ); - - wrapper.find('.euiModal__closeIcon').first().simulate('click'); - expect(onCloseCaseModal).toBeCalled(); - }); - - it('pass the correct props to FormContext component', () => { - const wrapper = mount( - <TestProviders> - <CreateCaseModal {...defaultProps} /> - </TestProviders> - ); - - const props = wrapper.find('FormContext').props(); - expect(props).toEqual( - expect.objectContaining({ - onSuccess, - }) - ); - }); - - it('onSuccess called when creating a case', () => { - const wrapper = mount( - <TestProviders> - <CreateCaseModal {...defaultProps} /> - </TestProviders> - ); - - wrapper.find(`[data-test-subj='form-context-on-success']`).first().simulate('click'); - expect(onSuccess).toHaveBeenCalledWith({ id: 'case-id' }); - }); -}); diff --git a/x-pack/plugins/cases/public/components/use_create_case_modal/create_case_modal.tsx b/x-pack/plugins/cases/public/components/use_create_case_modal/create_case_modal.tsx deleted file mode 100644 index fc397b24e704..000000000000 --- a/x-pack/plugins/cases/public/components/use_create_case_modal/create_case_modal.tsx +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { memo } from 'react'; -import styled from 'styled-components'; -import { EuiModal, EuiModalBody, EuiModalHeader, EuiModalHeaderTitle } from '@elastic/eui'; - -import { FormContext } from '../create/form_context'; -import { CreateCaseForm } from '../create/form'; -import { SubmitCaseButton } from '../create/submit_button'; -import { Case } from '../../containers/types'; -import * as i18n from '../../common/translations'; -import { CaseType } from '../../../common'; - -export interface CreateCaseModalProps { - isModalOpen: boolean; - onCloseCaseModal: () => void; - onSuccess: (theCase: Case) => Promise<void>; - caseType?: CaseType; - hideConnectorServiceNowSir?: boolean; -} - -const Container = styled.div` - ${({ theme }) => ` - margin-top: ${theme.eui.euiSize}; - text-align: right; - `} -`; - -const CreateModalComponent: React.FC<CreateCaseModalProps> = ({ - isModalOpen, - onCloseCaseModal, - onSuccess, - caseType = CaseType.individual, - hideConnectorServiceNowSir = false, -}) => { - return isModalOpen ? ( - <EuiModal onClose={onCloseCaseModal} data-test-subj="all-cases-modal"> - <EuiModalHeader> - <EuiModalHeaderTitle>{i18n.CREATE_TITLE}</EuiModalHeaderTitle> - </EuiModalHeader> - <EuiModalBody> - <FormContext - hideConnectorServiceNowSir={hideConnectorServiceNowSir} - caseType={caseType} - onSuccess={onSuccess} - > - <CreateCaseForm - withSteps={false} - hideConnectorServiceNowSir={hideConnectorServiceNowSir} - /> - <Container> - <SubmitCaseButton /> - </Container> - </FormContext> - </EuiModalBody> - </EuiModal> - ) : null; -}; - -export const CreateCaseModal = memo(CreateModalComponent); - -CreateCaseModal.displayName = 'CreateCaseModal'; diff --git a/x-pack/plugins/cases/public/components/use_create_case_modal/index.test.tsx b/x-pack/plugins/cases/public/components/use_create_case_modal/index.test.tsx deleted file mode 100644 index df9e6f0af60d..000000000000 --- a/x-pack/plugins/cases/public/components/use_create_case_modal/index.test.tsx +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { ReactNode } from 'react'; -import { renderHook, act } from '@testing-library/react-hooks'; -import { render, screen } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; - -import { useKibana } from '../../common/lib/kibana'; -import { useCreateCaseModal, UseCreateCaseModalProps, UseCreateCaseModalReturnedValues } from '.'; -import { TestProviders } from '../../common/mock'; - -jest.mock('../../common/lib/kibana'); -jest.mock('../create/form_context', () => { - return { - FormContext: ({ - children, - onSuccess, - }: { - children: ReactNode; - onSuccess: ({ id }: { id: string }) => Promise<void>; - }) => { - return ( - <> - <button - type="button" - data-test-subj="form-context-on-success" - onClick={async () => { - await onSuccess({ id: 'case-id' }); - }} - > - {'Form submit'} - </button> - {children} - </> - ); - }, - }; -}); - -jest.mock('../create/form', () => { - return { - CreateCaseForm: () => { - return <>{'form'}</>; - }, - }; -}); - -jest.mock('../create/submit_button', () => { - return { - SubmitCaseButton: () => { - return <>{'Submit'}</>; - }, - }; -}); - -const useKibanaMock = useKibana as jest.Mocked<typeof useKibana>; -const onCaseCreated = jest.fn(); - -describe('useCreateCaseModal', () => { - let navigateToApp: jest.Mock; - - beforeEach(() => { - navigateToApp = jest.fn(); - useKibanaMock().services.application.navigateToApp = navigateToApp; - }); - - it('init', async () => { - const { result } = renderHook<UseCreateCaseModalProps, UseCreateCaseModalReturnedValues>( - () => useCreateCaseModal({ onCaseCreated }), - { - wrapper: ({ children }) => <TestProviders>{children}</TestProviders>, - } - ); - - expect(result.current.isModalOpen).toBe(false); - }); - - it('opens the modal', async () => { - const { result } = renderHook<UseCreateCaseModalProps, UseCreateCaseModalReturnedValues>( - () => useCreateCaseModal({ onCaseCreated }), - { - wrapper: ({ children }) => <TestProviders>{children}</TestProviders>, - } - ); - - act(() => { - result.current.openModal(); - }); - - expect(result.current.isModalOpen).toBe(true); - }); - - it('closes the modal', async () => { - const { result } = renderHook<UseCreateCaseModalProps, UseCreateCaseModalReturnedValues>( - () => useCreateCaseModal({ onCaseCreated }), - { - wrapper: ({ children }) => <TestProviders>{children}</TestProviders>, - } - ); - - act(() => { - result.current.openModal(); - result.current.closeModal(); - }); - - expect(result.current.isModalOpen).toBe(false); - }); - - it('returns a memoized value', async () => { - const { result, rerender } = renderHook< - UseCreateCaseModalProps, - UseCreateCaseModalReturnedValues - >(() => useCreateCaseModal({ onCaseCreated }), { - wrapper: ({ children }) => <TestProviders>{children}</TestProviders>, - }); - - const result1 = result.current; - act(() => rerender()); - const result2 = result.current; - - expect(Object.is(result1, result2)).toBe(true); - }); - - it('closes the modal when creating a case', async () => { - const { result } = renderHook<UseCreateCaseModalProps, UseCreateCaseModalReturnedValues>( - () => useCreateCaseModal({ onCaseCreated }), - { - wrapper: ({ children }) => <TestProviders>{children}</TestProviders>, - } - ); - - act(() => { - result.current.openModal(); - }); - - const modal = result.current.modal; - render(<TestProviders>{modal}</TestProviders>); - - act(() => { - userEvent.click(screen.getByText('Form submit')); - }); - - expect(result.current.isModalOpen).toBe(false); - expect(onCaseCreated).toHaveBeenCalledWith({ id: 'case-id' }); - }); -}); diff --git a/x-pack/plugins/cases/public/components/use_create_case_modal/index.tsx b/x-pack/plugins/cases/public/components/use_create_case_modal/index.tsx deleted file mode 100644 index 7da3f49be721..000000000000 --- a/x-pack/plugins/cases/public/components/use_create_case_modal/index.tsx +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { useState, useCallback, useMemo } from 'react'; -import { CaseType } from '../../../common'; -import { Case } from '../../containers/types'; -import { CreateCaseModal } from './create_case_modal'; - -export interface UseCreateCaseModalProps { - onCaseCreated: (theCase: Case) => void; - caseType?: CaseType; - hideConnectorServiceNowSir?: boolean; -} -export interface UseCreateCaseModalReturnedValues { - modal: JSX.Element; - isModalOpen: boolean; - closeModal: () => void; - openModal: () => void; -} - -export const useCreateCaseModal = ({ - caseType = CaseType.individual, - onCaseCreated, - hideConnectorServiceNowSir = false, -}: UseCreateCaseModalProps) => { - const [isModalOpen, setIsModalOpen] = useState<boolean>(false); - const closeModal = useCallback(() => setIsModalOpen(false), []); - const openModal = useCallback(() => setIsModalOpen(true), []); - const onSuccess = useCallback( - async (theCase) => { - onCaseCreated(theCase); - closeModal(); - }, - [onCaseCreated, closeModal] - ); - - const state = useMemo( - () => ({ - modal: ( - <CreateCaseModal - caseType={caseType} - hideConnectorServiceNowSir={hideConnectorServiceNowSir} - isModalOpen={isModalOpen} - onCloseCaseModal={closeModal} - onSuccess={onSuccess} - /> - ), - isModalOpen, - closeModal, - openModal, - }), - [caseType, closeModal, hideConnectorServiceNowSir, isModalOpen, onSuccess, openModal] - ); - - return state; -}; diff --git a/x-pack/plugins/cases/public/components/wrappers/index.tsx b/x-pack/plugins/cases/public/components/wrappers/index.tsx deleted file mode 100644 index 3b33e9304da8..000000000000 --- a/x-pack/plugins/cases/public/components/wrappers/index.tsx +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import styled from 'styled-components'; - -export const WhitePageWrapper = styled.div` - background-color: ${({ theme }) => theme.eui.euiColorEmptyShade}; - border-top: ${({ theme }) => theme.eui.euiBorderThin}; - flex: 1 1 auto; -`; - -export const SectionWrapper = styled.div` - box-sizing: content-box; - margin: 0 auto; - max-width: 1175px; - width: 100%; -`; - -export const HeaderWrapper = styled.div` - padding: ${({ theme }) => - `${theme.eui.paddingSizes.l} ${theme.eui.paddingSizes.l} 0 ${theme.eui.paddingSizes.l}`}; -`; diff --git a/x-pack/plugins/cases/public/containers/__mocks__/api.ts b/x-pack/plugins/cases/public/containers/__mocks__/api.ts deleted file mode 100644 index 4dbb10da95b2..000000000000 --- a/x-pack/plugins/cases/public/containers/__mocks__/api.ts +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - ActionLicense, - AllCases, - BulkUpdateStatus, - Case, - CasesStatus, - CaseUserActions, - FetchCasesProps, - SortFieldCase, -} from '../types'; -import { - actionLicenses, - allCases, - basicCase, - basicCaseCommentPatch, - basicCasePost, - casesStatus, - caseUserActions, - pushedCase, - respReporters, - tags, -} from '../mock'; -import { - CasePatchRequest, - CasePostRequest, - CommentRequest, - User, - CaseStatuses, -} from '../../../common'; - -export const getCase = async ( - caseId: string, - includeComments: boolean = true, - signal: AbortSignal -): Promise<Case> => { - return Promise.resolve(basicCase); -}; - -export const getCasesStatus = async (signal: AbortSignal): Promise<CasesStatus> => - Promise.resolve(casesStatus); - -export const getTags = async (signal: AbortSignal): Promise<string[]> => Promise.resolve(tags); - -export const getReporters = async (signal: AbortSignal): Promise<User[]> => - Promise.resolve(respReporters); - -export const getCaseUserActions = async ( - caseId: string, - signal: AbortSignal -): Promise<CaseUserActions[]> => Promise.resolve(caseUserActions); - -export const getCases = async ({ - filterOptions = { - search: '', - reporters: [], - status: CaseStatuses.open, - tags: [], - }, - queryParams = { - page: 1, - perPage: 5, - sortField: SortFieldCase.createdAt, - sortOrder: 'desc', - }, - signal, -}: FetchCasesProps): Promise<AllCases> => Promise.resolve(allCases); - -export const postCase = async (newCase: CasePostRequest, signal: AbortSignal): Promise<Case> => - Promise.resolve(basicCasePost); - -export const patchCase = async ( - caseId: string, - updatedCase: Pick<CasePatchRequest, 'description' | 'status' | 'tags' | 'title'>, - version: string, - signal: AbortSignal -): Promise<Case[]> => Promise.resolve([basicCase]); - -export const patchCasesStatus = async ( - cases: BulkUpdateStatus[], - signal: AbortSignal -): Promise<Case[]> => Promise.resolve(allCases.cases); - -export const postComment = async ( - newComment: CommentRequest, - caseId: string, - signal: AbortSignal -): Promise<Case> => Promise.resolve(basicCase); - -export const patchComment = async ( - caseId: string, - commentId: string, - commentUpdate: string, - version: string, - signal: AbortSignal -): Promise<Case> => Promise.resolve(basicCaseCommentPatch); - -export const deleteCases = async (caseIds: string[], signal: AbortSignal): Promise<boolean> => - Promise.resolve(true); - -export const pushCase = async ( - caseId: string, - connectorId: string, - signal: AbortSignal -): Promise<Case> => Promise.resolve(pushedCase); - -export const getActionLicense = async (signal: AbortSignal): Promise<ActionLicense[]> => - Promise.resolve(actionLicenses); diff --git a/x-pack/plugins/cases/public/containers/api.test.tsx b/x-pack/plugins/cases/public/containers/api.test.tsx deleted file mode 100644 index 3e71a05df7cc..000000000000 --- a/x-pack/plugins/cases/public/containers/api.test.tsx +++ /dev/null @@ -1,465 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { KibanaServices } from '../common/lib/kibana'; - -import { ConnectorTypes, CommentType, CaseStatuses } from '../../common'; -import { CASES_URL } from '../../common'; - -import { - deleteCases, - getActionLicense, - getCase, - getCases, - getCasesStatus, - getCaseUserActions, - getReporters, - getTags, - patchCase, - patchCasesStatus, - patchComment, - postCase, - postComment, - pushCase, -} from './api'; - -import { - actionLicenses, - allCases, - basicCase, - allCasesSnake, - basicCaseSnake, - pushedCaseSnake, - casesStatus, - casesSnake, - cases, - caseUserActions, - pushedCase, - reporters, - respReporters, - tags, - caseUserActionsSnake, - casesStatusSnake, -} from './mock'; - -import { DEFAULT_FILTER_OPTIONS, DEFAULT_QUERY_PARAMS } from './use_get_cases'; - -const abortCtrl = new AbortController(); -const mockKibanaServices = KibanaServices.get as jest.Mock; -jest.mock('../common/lib/kibana'); - -const fetchMock = jest.fn(); -mockKibanaServices.mockReturnValue({ http: { fetch: fetchMock } }); - -describe('Case Configuration API', () => { - describe('deleteCases', () => { - beforeEach(() => { - fetchMock.mockClear(); - fetchMock.mockResolvedValue(''); - }); - const data = ['1', '2']; - - test('check url, method, signal', async () => { - await deleteCases(data, abortCtrl.signal); - expect(fetchMock).toHaveBeenCalledWith(`${CASES_URL}`, { - method: 'DELETE', - query: { ids: JSON.stringify(data) }, - signal: abortCtrl.signal, - }); - }); - - test('happy path', async () => { - const resp = await deleteCases(data, abortCtrl.signal); - expect(resp).toEqual(''); - }); - }); - - describe('getActionLicense', () => { - beforeEach(() => { - fetchMock.mockClear(); - fetchMock.mockResolvedValue(actionLicenses); - }); - - test('check url, method, signal', async () => { - await getActionLicense(abortCtrl.signal); - expect(fetchMock).toHaveBeenCalledWith(`/api/actions/list_action_types`, { - method: 'GET', - signal: abortCtrl.signal, - }); - }); - - test('happy path', async () => { - const resp = await getActionLicense(abortCtrl.signal); - expect(resp).toEqual(actionLicenses); - }); - }); - - describe('getCase', () => { - beforeEach(() => { - fetchMock.mockClear(); - fetchMock.mockResolvedValue(basicCaseSnake); - }); - const data = basicCase.id; - - test('check url, method, signal', async () => { - await getCase(data, true, abortCtrl.signal); - expect(fetchMock).toHaveBeenCalledWith(`${CASES_URL}/${basicCase.id}`, { - method: 'GET', - query: { includeComments: true }, - signal: abortCtrl.signal, - }); - }); - - test('happy path', async () => { - const resp = await getCase(data, true, abortCtrl.signal); - expect(resp).toEqual(basicCase); - }); - }); - - describe('getCases', () => { - beforeEach(() => { - fetchMock.mockClear(); - fetchMock.mockResolvedValue(allCasesSnake); - }); - test('check url, method, signal', async () => { - await getCases({ - filterOptions: DEFAULT_FILTER_OPTIONS, - queryParams: DEFAULT_QUERY_PARAMS, - signal: abortCtrl.signal, - }); - expect(fetchMock).toHaveBeenCalledWith(`${CASES_URL}/_find`, { - method: 'GET', - query: { - ...DEFAULT_QUERY_PARAMS, - reporters: [], - tags: [], - }, - signal: abortCtrl.signal, - }); - }); - - test('correctly applies filters', async () => { - await getCases({ - filterOptions: { - ...DEFAULT_FILTER_OPTIONS, - reporters: [...respReporters, { username: null, full_name: null, email: null }], - tags, - status: CaseStatuses.open, - search: 'hello', - }, - queryParams: DEFAULT_QUERY_PARAMS, - signal: abortCtrl.signal, - }); - expect(fetchMock).toHaveBeenCalledWith(`${CASES_URL}/_find`, { - method: 'GET', - query: { - ...DEFAULT_QUERY_PARAMS, - reporters, - tags: ['"coke"', '"pepsi"'], - search: 'hello', - status: CaseStatuses.open, - }, - signal: abortCtrl.signal, - }); - }); - - test('tags with weird chars get handled gracefully', async () => { - const weirdTags: string[] = ['(', '"double"']; - - await getCases({ - filterOptions: { - ...DEFAULT_FILTER_OPTIONS, - reporters: [...respReporters, { username: null, full_name: null, email: null }], - tags: weirdTags, - status: CaseStatuses.open, - search: 'hello', - }, - queryParams: DEFAULT_QUERY_PARAMS, - signal: abortCtrl.signal, - }); - expect(fetchMock).toHaveBeenCalledWith(`${CASES_URL}/_find`, { - method: 'GET', - query: { - ...DEFAULT_QUERY_PARAMS, - reporters, - tags: ['"("', '"\\"double\\""'], - search: 'hello', - status: CaseStatuses.open, - }, - signal: abortCtrl.signal, - }); - }); - - test('happy path', async () => { - const resp = await getCases({ - filterOptions: DEFAULT_FILTER_OPTIONS, - queryParams: DEFAULT_QUERY_PARAMS, - signal: abortCtrl.signal, - }); - expect(resp).toEqual({ ...allCases }); - }); - }); - - describe('getCasesStatus', () => { - beforeEach(() => { - fetchMock.mockClear(); - fetchMock.mockResolvedValue(casesStatusSnake); - }); - test('check url, method, signal', async () => { - await getCasesStatus(abortCtrl.signal); - expect(fetchMock).toHaveBeenCalledWith(`${CASES_URL}/status`, { - method: 'GET', - signal: abortCtrl.signal, - }); - }); - - test('happy path', async () => { - const resp = await getCasesStatus(abortCtrl.signal); - expect(resp).toEqual(casesStatus); - }); - }); - - describe('getCaseUserActions', () => { - beforeEach(() => { - fetchMock.mockClear(); - fetchMock.mockResolvedValue(caseUserActionsSnake); - }); - - test('check url, method, signal', async () => { - await getCaseUserActions(basicCase.id, abortCtrl.signal); - expect(fetchMock).toHaveBeenCalledWith(`${CASES_URL}/${basicCase.id}/user_actions`, { - method: 'GET', - signal: abortCtrl.signal, - }); - }); - - test('happy path', async () => { - const resp = await getCaseUserActions(basicCase.id, abortCtrl.signal); - expect(resp).toEqual(caseUserActions); - }); - }); - - describe('getReporters', () => { - beforeEach(() => { - fetchMock.mockClear(); - fetchMock.mockResolvedValue(respReporters); - }); - - test('check url, method, signal', async () => { - await getReporters(abortCtrl.signal); - expect(fetchMock).toHaveBeenCalledWith(`${CASES_URL}/reporters`, { - method: 'GET', - signal: abortCtrl.signal, - }); - }); - - test('happy path', async () => { - const resp = await getReporters(abortCtrl.signal); - expect(resp).toEqual(respReporters); - }); - }); - - describe('getTags', () => { - beforeEach(() => { - fetchMock.mockClear(); - fetchMock.mockResolvedValue(tags); - }); - - test('check url, method, signal', async () => { - await getTags(abortCtrl.signal); - expect(fetchMock).toHaveBeenCalledWith(`${CASES_URL}/tags`, { - method: 'GET', - signal: abortCtrl.signal, - }); - }); - - test('happy path', async () => { - const resp = await getTags(abortCtrl.signal); - expect(resp).toEqual(tags); - }); - }); - - describe('patchCase', () => { - beforeEach(() => { - fetchMock.mockClear(); - fetchMock.mockResolvedValue([basicCaseSnake]); - }); - const data = { description: 'updated description' }; - test('check url, method, signal', async () => { - await patchCase(basicCase.id, data, basicCase.version, abortCtrl.signal); - expect(fetchMock).toHaveBeenCalledWith(`${CASES_URL}`, { - method: 'PATCH', - body: JSON.stringify({ - cases: [{ ...data, id: basicCase.id, version: basicCase.version }], - }), - signal: abortCtrl.signal, - }); - }); - - test('happy path', async () => { - const resp = await patchCase( - basicCase.id, - { description: 'updated description' }, - basicCase.version, - abortCtrl.signal - ); - expect(resp).toEqual({ ...[basicCase] }); - }); - }); - - describe('patchCasesStatus', () => { - beforeEach(() => { - fetchMock.mockClear(); - fetchMock.mockResolvedValue(casesSnake); - }); - const data = [ - { - status: CaseStatuses.closed, - id: basicCase.id, - version: basicCase.version, - }, - ]; - - test('check url, method, signal', async () => { - await patchCasesStatus(data, abortCtrl.signal); - expect(fetchMock).toHaveBeenCalledWith(`${CASES_URL}`, { - method: 'PATCH', - body: JSON.stringify({ cases: data }), - signal: abortCtrl.signal, - }); - }); - - test('happy path', async () => { - const resp = await patchCasesStatus(data, abortCtrl.signal); - expect(resp).toEqual({ ...cases }); - }); - }); - - describe('patchComment', () => { - beforeEach(() => { - fetchMock.mockClear(); - fetchMock.mockResolvedValue(basicCaseSnake); - }); - - test('check url, method, signal', async () => { - await patchComment( - basicCase.id, - basicCase.comments[0].id, - 'updated comment', - basicCase.comments[0].version, - abortCtrl.signal - ); - expect(fetchMock).toHaveBeenCalledWith(`${CASES_URL}/${basicCase.id}/comments`, { - method: 'PATCH', - body: JSON.stringify({ - comment: 'updated comment', - type: CommentType.user, - id: basicCase.comments[0].id, - version: basicCase.comments[0].version, - }), - signal: abortCtrl.signal, - }); - }); - - test('happy path', async () => { - const resp = await patchComment( - basicCase.id, - basicCase.comments[0].id, - 'updated comment', - basicCase.comments[0].version, - abortCtrl.signal - ); - expect(resp).toEqual(basicCase); - }); - }); - - describe('postCase', () => { - beforeEach(() => { - fetchMock.mockClear(); - fetchMock.mockResolvedValue(basicCaseSnake); - }); - const data = { - description: 'description', - tags: ['tag'], - title: 'title', - connector: { - id: 'none', - name: 'none', - type: ConnectorTypes.none, - fields: null, - }, - settings: { - syncAlerts: true, - }, - }; - - test('check url, method, signal', async () => { - await postCase(data, abortCtrl.signal); - expect(fetchMock).toHaveBeenCalledWith(`${CASES_URL}`, { - method: 'POST', - body: JSON.stringify(data), - signal: abortCtrl.signal, - }); - }); - - test('happy path', async () => { - const resp = await postCase(data, abortCtrl.signal); - expect(resp).toEqual(basicCase); - }); - }); - - describe('postComment', () => { - beforeEach(() => { - fetchMock.mockClear(); - fetchMock.mockResolvedValue(basicCaseSnake); - }); - const data = { - comment: 'comment', - type: CommentType.user as const, - }; - - test('check url, method, signal', async () => { - await postComment(data, basicCase.id, abortCtrl.signal); - expect(fetchMock).toHaveBeenCalledWith(`${CASES_URL}/${basicCase.id}/comments`, { - method: 'POST', - body: JSON.stringify(data), - signal: abortCtrl.signal, - }); - }); - - test('happy path', async () => { - const resp = await postComment(data, basicCase.id, abortCtrl.signal); - expect(resp).toEqual(basicCase); - }); - }); - - describe('pushCase', () => { - const connectorId = 'connectorId'; - - beforeEach(() => { - fetchMock.mockClear(); - fetchMock.mockResolvedValue(pushedCaseSnake); - }); - - test('check url, method, signal', async () => { - await pushCase(basicCase.id, connectorId, abortCtrl.signal); - expect(fetchMock).toHaveBeenCalledWith( - `${CASES_URL}/${basicCase.id}/connector/${connectorId}/_push`, - { - method: 'POST', - body: JSON.stringify({}), - signal: abortCtrl.signal, - } - ); - }); - - test('happy path', async () => { - const resp = await pushCase(basicCase.id, connectorId, abortCtrl.signal); - expect(resp).toEqual(pushedCase); - }); - }); -}); diff --git a/x-pack/plugins/cases/public/containers/api.ts b/x-pack/plugins/cases/public/containers/api.ts deleted file mode 100644 index 5827083bfdbd..000000000000 --- a/x-pack/plugins/cases/public/containers/api.ts +++ /dev/null @@ -1,347 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { assign, omit } from 'lodash'; - -import { - CasePatchRequest, - CasePostRequest, - CaseResponse, - CasesFindResponse, - CasesResponse, - CasesStatusResponse, - CaseType, - CaseUserActionsResponse, - CommentRequest, - CommentType, - 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 { StatusAll } from '../components/status'; - -import { - ActionLicense, - AllCases, - BulkUpdateStatus, - Case, - CasesStatus, - FetchCasesProps, - SortFieldCase, - CaseUserActions, -} from './types'; - -import { - convertToCamelCase, - convertAllCasesToCamel, - convertArrayToCamelCase, - decodeCaseResponse, - decodeCasesResponse, - decodeCasesFindResponse, - decodeCasesStatusResponse, - decodeCaseUserActionsResponse, -} from './utils'; - -export const getCase = async ( - caseId: string, - includeComments: boolean = true, - signal: AbortSignal -): Promise<Case> => { - const response = await KibanaServices.get().http.fetch<CaseResponse>(getCaseDetailsUrl(caseId), { - method: 'GET', - query: { - includeComments, - }, - signal, - }); - return convertToCamelCase<CaseResponse, Case>(decodeCaseResponse(response)); -}; - -export const getSubCase = async ( - caseId: string, - subCaseId: string, - includeComments: boolean = true, - signal: AbortSignal -): Promise<Case> => { - const [caseResponse, subCaseResponse] = await Promise.all([ - KibanaServices.get().http.fetch<CaseResponse>(getCaseDetailsUrl(caseId), { - method: 'GET', - query: { - includeComments: false, - }, - signal, - }), - KibanaServices.get().http.fetch<SubCaseResponse>(getSubCaseDetailsUrl(caseId, subCaseId), { - method: 'GET', - query: { - includeComments, - }, - signal, - }), - ]); - const response = assign<CaseResponse, SubCaseResponse>(caseResponse, subCaseResponse); - const subCaseIndex = response.subCaseIds?.findIndex((scId) => scId === response.id) ?? -1; - response.title = `${response.title}${subCaseIndex >= 0 ? ` ${subCaseIndex + 1}` : ''}`; - return convertToCamelCase<CaseResponse, Case>(decodeCaseResponse(response)); -}; - -export const getCasesStatus = async (signal: AbortSignal): Promise<CasesStatus> => { - const response = await KibanaServices.get().http.fetch<CasesStatusResponse>(CASE_STATUS_URL, { - method: 'GET', - signal, - }); - return convertToCamelCase<CasesStatusResponse, CasesStatus>(decodeCasesStatusResponse(response)); -}; - -export const getTags = async (signal: AbortSignal): Promise<string[]> => { - const response = await KibanaServices.get().http.fetch<string[]>(CASE_TAGS_URL, { - method: 'GET', - signal, - }); - return response ?? []; -}; - -export const getReporters = async (signal: AbortSignal): Promise<User[]> => { - const response = await KibanaServices.get().http.fetch<User[]>(CASE_REPORTERS_URL, { - method: 'GET', - signal, - }); - return response ?? []; -}; - -export const getCaseUserActions = async ( - caseId: string, - signal: AbortSignal -): Promise<CaseUserActions[]> => { - const response = await KibanaServices.get().http.fetch<CaseUserActionsResponse>( - getCaseUserActionUrl(caseId), - { - method: 'GET', - signal, - } - ); - return convertArrayToCamelCase(decodeCaseUserActionsResponse(response)) as CaseUserActions[]; -}; - -export const getSubCaseUserActions = async ( - caseId: string, - subCaseId: string, - signal: AbortSignal -): Promise<CaseUserActions[]> => { - const response = await KibanaServices.get().http.fetch<CaseUserActionsResponse>( - getSubCaseUserActionUrl(caseId, subCaseId), - { - method: 'GET', - signal, - } - ); - return convertArrayToCamelCase(decodeCaseUserActionsResponse(response)) as CaseUserActions[]; -}; - -export const getCases = async ({ - filterOptions = { - onlyCollectionType: false, - search: '', - reporters: [], - status: StatusAll, - tags: [], - }, - queryParams = { - page: 1, - perPage: 20, - sortField: SortFieldCase.createdAt, - sortOrder: 'desc', - }, - signal, -}: FetchCasesProps): Promise<AllCases> => { - const query = { - reporters: filterOptions.reporters.map((r) => r.username ?? '').filter((r) => r !== ''), - tags: filterOptions.tags.map((t) => `"${t.replace(/"/g, '\\"')}"`), - status: filterOptions.status, - ...(filterOptions.search.length > 0 ? { search: filterOptions.search } : {}), - ...(filterOptions.onlyCollectionType ? { type: CaseType.collection } : {}), - ...queryParams, - }; - const response = await KibanaServices.get().http.fetch<CasesFindResponse>(`${CASES_URL}/_find`, { - method: 'GET', - query: query.status === StatusAll ? omit(query, ['status']) : query, - signal, - }); - return convertAllCasesToCamel(decodeCasesFindResponse(response)); -}; - -export const postCase = async (newCase: CasePostRequest, signal: AbortSignal): Promise<Case> => { - const response = await KibanaServices.get().http.fetch<CaseResponse>(CASES_URL, { - method: 'POST', - body: JSON.stringify(newCase), - signal, - }); - return convertToCamelCase<CaseResponse, Case>(decodeCaseResponse(response)); -}; - -export const patchCase = async ( - caseId: string, - updatedCase: Pick< - CasePatchRequest, - 'description' | 'status' | 'tags' | 'title' | 'settings' | 'connector' - >, - version: string, - signal: AbortSignal -): Promise<Case[]> => { - const response = await KibanaServices.get().http.fetch<CasesResponse>(CASES_URL, { - method: 'PATCH', - body: JSON.stringify({ cases: [{ ...updatedCase, id: caseId, version }] }), - signal, - }); - return convertToCamelCase<CasesResponse, Case[]>(decodeCasesResponse(response)); -}; - -export const patchSubCase = async ( - caseId: string, - subCaseId: string, - updatedSubCase: Pick<SubCasePatchRequest, 'status'>, - version: string, - signal: AbortSignal -): Promise<Case[]> => { - const subCaseResponse = await KibanaServices.get().http.fetch<SubCasesResponse>( - SUB_CASE_DETAILS_URL, - { - method: 'PATCH', - body: JSON.stringify({ cases: [{ ...updatedSubCase, id: caseId, version }] }), - signal, - } - ); - const caseResponse = await KibanaServices.get().http.fetch<CaseResponse>( - getCaseDetailsUrl(caseId), - { - method: 'GET', - query: { - includeComments: false, - }, - signal, - } - ); - const response = subCaseResponse.map((subCaseResp) => assign(caseResponse, subCaseResp)); - return convertToCamelCase<CasesResponse, Case[]>(decodeCasesResponse(response)); -}; - -export const patchCasesStatus = async ( - cases: BulkUpdateStatus[], - signal: AbortSignal -): Promise<Case[]> => { - const response = await KibanaServices.get().http.fetch<CasesResponse>(CASES_URL, { - method: 'PATCH', - body: JSON.stringify({ cases }), - signal, - }); - return convertToCamelCase<CasesResponse, Case[]>(decodeCasesResponse(response)); -}; - -export const postComment = async ( - newComment: CommentRequest, - caseId: string, - signal: AbortSignal, - subCaseId?: string -): Promise<Case> => { - const response = await KibanaServices.get().http.fetch<CaseResponse>( - `${CASES_URL}/${caseId}/comments`, - { - method: 'POST', - body: JSON.stringify(newComment), - ...(subCaseId ? { query: { subCaseId } } : {}), - signal, - } - ); - return convertToCamelCase<CaseResponse, Case>(decodeCaseResponse(response)); -}; - -export const patchComment = async ( - caseId: string, - commentId: string, - commentUpdate: string, - version: string, - signal: AbortSignal, - subCaseId?: string -): Promise<Case> => { - const response = await KibanaServices.get().http.fetch<CaseResponse>(getCaseCommentsUrl(caseId), { - method: 'PATCH', - body: JSON.stringify({ - comment: commentUpdate, - type: CommentType.user, - id: commentId, - version, - }), - ...(subCaseId ? { query: { subCaseId } } : {}), - signal, - }); - return convertToCamelCase<CaseResponse, Case>(decodeCaseResponse(response)); -}; - -export const deleteCases = async (caseIds: string[], signal: AbortSignal): Promise<string> => { - const response = await KibanaServices.get().http.fetch<string>(CASES_URL, { - method: 'DELETE', - query: { ids: JSON.stringify(caseIds) }, - signal, - }); - return response; -}; - -export const deleteSubCases = async (caseIds: string[], signal: AbortSignal): Promise<string> => { - const response = await KibanaServices.get().http.fetch<string>(SUB_CASES_PATCH_DEL_URL, { - method: 'DELETE', - query: { ids: JSON.stringify(caseIds) }, - signal, - }); - return response; -}; - -export const pushCase = async ( - caseId: string, - connectorId: string, - signal: AbortSignal -): Promise<Case> => { - const response = await KibanaServices.get().http.fetch<CaseResponse>( - getCasePushUrl(caseId, connectorId), - { - method: 'POST', - body: JSON.stringify({}), - signal, - } - ); - - return convertToCamelCase<CaseResponse, Case>(decodeCaseResponse(response)); -}; - -export const getActionLicense = async (signal: AbortSignal): Promise<ActionLicense[]> => { - const response = await KibanaServices.get().http.fetch<ActionLicense[]>(ACTION_TYPES_URL, { - method: 'GET', - signal, - }); - return response; -}; diff --git a/x-pack/plugins/cases/public/containers/configure/__mocks__/api.ts b/x-pack/plugins/cases/public/containers/configure/__mocks__/api.ts deleted file mode 100644 index ea4b92706b4d..000000000000 --- a/x-pack/plugins/cases/public/containers/configure/__mocks__/api.ts +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - CasesConfigurePatch, - CasesConfigureRequest, - ActionConnector, - ActionTypeConnector, -} from '../../../../common'; - -import { ApiProps } from '../../types'; -import { CaseConfigure } from '../types'; -import { connectorsMock, caseConfigurationCamelCaseResponseMock, actionTypesMock } from '../mock'; - -export const fetchConnectors = async ({ signal }: ApiProps): Promise<ActionConnector[]> => - Promise.resolve(connectorsMock); - -export const getCaseConfigure = async ({ signal }: ApiProps): Promise<CaseConfigure> => - Promise.resolve(caseConfigurationCamelCaseResponseMock); - -export const postCaseConfigure = async ( - caseConfiguration: CasesConfigureRequest, - signal: AbortSignal -): Promise<CaseConfigure> => Promise.resolve(caseConfigurationCamelCaseResponseMock); - -export const patchCaseConfigure = async ( - caseConfiguration: CasesConfigurePatch, - signal: AbortSignal -): Promise<CaseConfigure> => Promise.resolve(caseConfigurationCamelCaseResponseMock); - -export const fetchActionTypes = async ({ signal }: ApiProps): Promise<ActionTypeConnector[]> => - Promise.resolve(actionTypesMock); diff --git a/x-pack/plugins/cases/public/containers/configure/api.test.ts b/x-pack/plugins/cases/public/containers/configure/api.test.ts deleted file mode 100644 index ae749b439177..000000000000 --- a/x-pack/plugins/cases/public/containers/configure/api.test.ts +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - fetchConnectors, - getCaseConfigure, - postCaseConfigure, - patchCaseConfigure, - fetchActionTypes, -} from './api'; -import { - connectorsMock, - actionTypesMock, - caseConfigurationMock, - caseConfigurationResposeMock, - caseConfigurationCamelCaseResponseMock, -} from './mock'; -import { ConnectorTypes } from '../../../common'; -import { KibanaServices } from '../../common/lib/kibana'; - -const abortCtrl = new AbortController(); -const mockKibanaServices = KibanaServices.get as jest.Mock; -jest.mock('../../common/lib/kibana'); - -const fetchMock = jest.fn(); -mockKibanaServices.mockReturnValue({ http: { fetch: fetchMock } }); - -describe('Case Configuration API', () => { - describe('fetch connectors', () => { - beforeEach(() => { - fetchMock.mockClear(); - fetchMock.mockResolvedValue(connectorsMock); - }); - - test('check url, method, signal', async () => { - await fetchConnectors({ signal: abortCtrl.signal }); - expect(fetchMock).toHaveBeenCalledWith('/api/cases/configure/connectors/_find', { - method: 'GET', - signal: abortCtrl.signal, - }); - }); - - test('happy path', async () => { - const resp = await fetchConnectors({ signal: abortCtrl.signal }); - expect(resp).toEqual(connectorsMock); - }); - }); - - describe('fetch configuration', () => { - beforeEach(() => { - fetchMock.mockClear(); - fetchMock.mockResolvedValue(caseConfigurationResposeMock); - }); - - test('check url, method, signal', async () => { - await getCaseConfigure({ signal: abortCtrl.signal }); - expect(fetchMock).toHaveBeenCalledWith('/api/cases/configure', { - method: 'GET', - signal: abortCtrl.signal, - }); - }); - - test('happy path', async () => { - const resp = await getCaseConfigure({ signal: abortCtrl.signal }); - expect(resp).toEqual(caseConfigurationCamelCaseResponseMock); - }); - - test('return null on empty response', async () => { - fetchMock.mockResolvedValue({}); - const resp = await getCaseConfigure({ signal: abortCtrl.signal }); - expect(resp).toBe(null); - }); - }); - - describe('create configuration', () => { - beforeEach(() => { - fetchMock.mockClear(); - fetchMock.mockResolvedValue(caseConfigurationResposeMock); - }); - - test('check url, body, method, signal', async () => { - await postCaseConfigure(caseConfigurationMock, abortCtrl.signal); - expect(fetchMock).toHaveBeenCalledWith('/api/cases/configure', { - body: - '{"connector":{"id":"123","name":"My connector","type":".jira","fields":null},"closure_type":"close-by-user"}', - method: 'POST', - signal: abortCtrl.signal, - }); - }); - - test('happy path', async () => { - const resp = await postCaseConfigure(caseConfigurationMock, abortCtrl.signal); - expect(resp).toEqual(caseConfigurationCamelCaseResponseMock); - }); - }); - - describe('update configuration', () => { - beforeEach(() => { - fetchMock.mockClear(); - fetchMock.mockResolvedValue(caseConfigurationResposeMock); - }); - - test('check url, body, method, signal', async () => { - await patchCaseConfigure( - { - connector: { id: '456', name: 'My Connector 2', type: ConnectorTypes.none, fields: null }, - version: 'WzHJ12', - }, - abortCtrl.signal - ); - expect(fetchMock).toHaveBeenCalledWith('/api/cases/configure', { - body: - '{"connector":{"id":"456","name":"My Connector 2","type":".none","fields":null},"version":"WzHJ12"}', - method: 'PATCH', - signal: abortCtrl.signal, - }); - }); - - test('happy path', async () => { - const resp = await patchCaseConfigure( - { - connector: { id: '456', name: 'My Connector 2', type: ConnectorTypes.none, fields: null }, - version: 'WzHJ12', - }, - abortCtrl.signal - ); - expect(resp).toEqual(caseConfigurationCamelCaseResponseMock); - }); - }); - - describe('fetch actionTypes', () => { - beforeEach(() => { - fetchMock.mockClear(); - fetchMock.mockResolvedValue(actionTypesMock); - }); - - test('check url, method, signal', async () => { - await fetchActionTypes({ signal: abortCtrl.signal }); - expect(fetchMock).toHaveBeenCalledWith('/api/actions/list_action_types', { - method: 'GET', - signal: abortCtrl.signal, - }); - }); - - test('happy path', async () => { - const resp = await fetchActionTypes({ signal: abortCtrl.signal }); - expect(resp).toEqual(actionTypesMock); - }); - }); -}); diff --git a/x-pack/plugins/cases/public/containers/configure/api.ts b/x-pack/plugins/cases/public/containers/configure/api.ts deleted file mode 100644 index 006370fcb553..000000000000 --- a/x-pack/plugins/cases/public/containers/configure/api.ts +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { isEmpty } from 'lodash/fp'; -import { - ActionConnector, - ActionTypeConnector, - CasesConfigurePatch, - CasesConfigureResponse, - CasesConfigureRequest, -} from '../../../common'; -import { KibanaServices } from '../../common/lib/kibana'; - -import { - CASE_CONFIGURE_CONNECTORS_URL, - CASE_CONFIGURE_URL, - ACTION_TYPES_URL, -} from '../../../common'; - -import { ApiProps } from '../types'; -import { convertToCamelCase, decodeCaseConfigureResponse } from '../utils'; -import { CaseConfigure } from './types'; - -export const fetchConnectors = async ({ signal }: ApiProps): Promise<ActionConnector[]> => { - const response = await KibanaServices.get().http.fetch(`${CASE_CONFIGURE_CONNECTORS_URL}/_find`, { - method: 'GET', - signal, - }); - - return response; -}; - -export const getCaseConfigure = async ({ signal }: ApiProps): Promise<CaseConfigure | null> => { - const response = await KibanaServices.get().http.fetch<CasesConfigureResponse>( - CASE_CONFIGURE_URL, - { - method: 'GET', - signal, - } - ); - - return !isEmpty(response) - ? convertToCamelCase<CasesConfigureResponse, CaseConfigure>( - decodeCaseConfigureResponse(response) - ) - : null; -}; - -export const getConnectorMappings = async ({ signal }: ApiProps): Promise<ActionConnector[]> => { - const response = await KibanaServices.get().http.fetch(`${CASE_CONFIGURE_CONNECTORS_URL}/_find`, { - method: 'GET', - signal, - }); - - return response; -}; - -export const postCaseConfigure = async ( - caseConfiguration: CasesConfigureRequest, - signal: AbortSignal -): Promise<CaseConfigure> => { - const response = await KibanaServices.get().http.fetch<CasesConfigureResponse>( - CASE_CONFIGURE_URL, - { - method: 'POST', - body: JSON.stringify(caseConfiguration), - signal, - } - ); - return convertToCamelCase<CasesConfigureResponse, CaseConfigure>( - decodeCaseConfigureResponse(response) - ); -}; - -export const patchCaseConfigure = async ( - caseConfiguration: CasesConfigurePatch, - signal: AbortSignal -): Promise<CaseConfigure> => { - const response = await KibanaServices.get().http.fetch<CasesConfigureResponse>( - CASE_CONFIGURE_URL, - { - method: 'PATCH', - body: JSON.stringify(caseConfiguration), - signal, - } - ); - return convertToCamelCase<CasesConfigureResponse, CaseConfigure>( - decodeCaseConfigureResponse(response) - ); -}; - -export const fetchActionTypes = async ({ signal }: ApiProps): Promise<ActionTypeConnector[]> => { - const response = await KibanaServices.get().http.fetch(ACTION_TYPES_URL, { - method: 'GET', - signal, - }); - - return response; -}; diff --git a/x-pack/plugins/cases/public/containers/configure/mock.ts b/x-pack/plugins/cases/public/containers/configure/mock.ts deleted file mode 100644 index 766452e3e58e..000000000000 --- a/x-pack/plugins/cases/public/containers/configure/mock.ts +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - ActionConnector, - ActionTypeConnector, - CasesConfigureResponse, - CasesConfigureRequest, - ConnectorTypes, -} from '../../../common'; -import { CaseConfigure, CaseConnectorMapping } from './types'; - -export const mappings: CaseConnectorMapping[] = [ - { - source: 'title', - target: 'short_description', - actionType: 'overwrite', - }, - { - source: 'description', - target: 'description', - actionType: 'overwrite', - }, - { - source: 'comments', - target: 'comments', - actionType: 'append', - }, -]; - -export const connectorsMock: ActionConnector[] = [ - { - id: 'servicenow-1', - actionTypeId: '.servicenow', - name: 'My Connector', - config: { - apiUrl: 'https://instance1.service-now.com', - }, - isPreconfigured: false, - }, - { - id: 'resilient-2', - actionTypeId: '.resilient', - name: 'My Connector 2', - config: { - apiUrl: 'https://test/', - orgId: '201', - }, - isPreconfigured: false, - }, - { - id: 'jira-1', - actionTypeId: '.jira', - name: 'Jira', - config: { - apiUrl: 'https://instance.atlassian.ne', - }, - isPreconfigured: false, - }, - { - id: 'servicenow-sir', - actionTypeId: '.servicenow-sir', - name: 'My Connector SIR', - config: { - apiUrl: 'https://instance1.service-now.com', - }, - isPreconfigured: false, - }, -]; - -export const actionTypesMock: ActionTypeConnector[] = [ - { - id: '.email', - name: 'Email', - minimumLicenseRequired: 'gold', - enabled: true, - enabledInConfig: true, - enabledInLicense: true, - }, - { - id: '.index', - name: 'Index', - minimumLicenseRequired: 'basic', - enabled: true, - enabledInConfig: true, - enabledInLicense: true, - }, - { - id: '.servicenow', - name: 'ServiceNow', - minimumLicenseRequired: 'platinum', - enabled: false, - enabledInConfig: true, - enabledInLicense: true, - }, - { - id: '.jira', - name: 'Jira', - minimumLicenseRequired: 'gold', - enabled: true, - enabledInConfig: true, - enabledInLicense: true, - }, - { - id: '.resilient', - name: 'IBM Resilient', - minimumLicenseRequired: 'platinum', - enabled: false, - enabledInConfig: true, - enabledInLicense: true, - }, -]; - -export const caseConfigurationResposeMock: CasesConfigureResponse = { - created_at: '2020-04-06T13:03:18.657Z', - created_by: { username: 'elastic', full_name: 'Elastic', email: 'elastic@elastic.co' }, - connector: { - id: '123', - name: 'My connector', - type: ConnectorTypes.jira, - fields: null, - }, - closure_type: 'close-by-pushing', - error: null, - mappings: [], - updated_at: '2020-04-06T14:03:18.657Z', - updated_by: { username: 'elastic', full_name: 'Elastic', email: 'elastic@elastic.co' }, - version: 'WzHJ12', -}; - -export const caseConfigurationMock: CasesConfigureRequest = { - connector: { - id: '123', - name: 'My connector', - type: ConnectorTypes.jira, - fields: null, - }, - closure_type: 'close-by-user', -}; - -export const caseConfigurationCamelCaseResponseMock: CaseConfigure = { - createdAt: '2020-04-06T13:03:18.657Z', - createdBy: { username: 'elastic', fullName: 'Elastic', email: 'elastic@elastic.co' }, - connector: { - id: '123', - name: 'My connector', - type: ConnectorTypes.jira, - fields: null, - }, - closureType: 'close-by-pushing', - error: null, - mappings: [], - updatedAt: '2020-04-06T14:03:18.657Z', - updatedBy: { username: 'elastic', fullName: 'Elastic', email: 'elastic@elastic.co' }, - version: 'WzHJ12', -}; diff --git a/x-pack/plugins/cases/public/containers/configure/translations.ts b/x-pack/plugins/cases/public/containers/configure/translations.ts deleted file mode 100644 index e77b9f57c8f4..000000000000 --- a/x-pack/plugins/cases/public/containers/configure/translations.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; - -export * from '../translations'; - -export const SUCCESS_CONFIGURE = i18n.translate('xpack.cases.configure.successSaveToast', { - defaultMessage: 'Saved external connection settings', -}); diff --git a/x-pack/plugins/cases/public/containers/configure/types.ts b/x-pack/plugins/cases/public/containers/configure/types.ts deleted file mode 100644 index b021ae2163fa..000000000000 --- a/x-pack/plugins/cases/public/containers/configure/types.ts +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { ElasticUser } from '../types'; -import { - ActionConnector, - ActionTypeConnector, - ActionType, - CaseConnector, - CaseField, - CasesConfigure, - ClosureType, - ThirdPartyField, -} from '../../../common'; - -export { - ActionConnector, - ActionTypeConnector, - ActionType, - CaseConnector, - CaseField, - ClosureType, - ThirdPartyField, -}; - -export interface CaseConnectorMapping { - actionType: ActionType; - source: CaseField; - target: string; -} - -export interface CaseConfigure { - closureType: ClosureType; - connector: CasesConfigure['connector']; - createdAt: string; - createdBy: ElasticUser; - error: string | null; - mappings: CaseConnectorMapping[]; - updatedAt: string; - updatedBy: ElasticUser; - version: string; -} diff --git a/x-pack/plugins/cases/public/containers/configure/use_action_types.test.tsx b/x-pack/plugins/cases/public/containers/configure/use_action_types.test.tsx deleted file mode 100644 index 25017f7931db..000000000000 --- a/x-pack/plugins/cases/public/containers/configure/use_action_types.test.tsx +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { renderHook, act } from '@testing-library/react-hooks'; -import { useActionTypes, UseActionTypesResponse } from './use_action_types'; -import { actionTypesMock } from './mock'; -import * as api from './api'; - -jest.mock('./api'); - -describe('useActionTypes', () => { - beforeEach(() => { - jest.clearAllMocks(); - jest.restoreAllMocks(); - }); - - test('init', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, UseActionTypesResponse>(() => - useActionTypes() - ); - await waitForNextUpdate(); - expect(result.current).toEqual({ - loading: true, - actionTypes: [], - refetchActionTypes: result.current.refetchActionTypes, - }); - }); - }); - - test('fetch action types', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, UseActionTypesResponse>(() => - useActionTypes() - ); - - await waitForNextUpdate(); - await waitForNextUpdate(); - - expect(result.current).toEqual({ - loading: false, - actionTypes: actionTypesMock, - refetchActionTypes: result.current.refetchActionTypes, - }); - }); - }); - - test('refetch actionTypes', async () => { - const spyOnfetchActionTypes = jest.spyOn(api, 'fetchActionTypes'); - await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, UseActionTypesResponse>(() => - useActionTypes() - ); - - await waitForNextUpdate(); - await waitForNextUpdate(); - - result.current.refetchActionTypes(); - expect(spyOnfetchActionTypes).toHaveBeenCalledTimes(2); - }); - }); - - test('set isLoading to true when refetching actionTypes', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, UseActionTypesResponse>(() => - useActionTypes() - ); - - await waitForNextUpdate(); - await waitForNextUpdate(); - - result.current.refetchActionTypes(); - - expect(result.current.loading).toBe(true); - }); - }); - - test('unhappy path', async () => { - const spyOnfetchActionTypes = jest.spyOn(api, 'fetchActionTypes'); - spyOnfetchActionTypes.mockImplementation(() => { - throw new Error('Something went wrong'); - }); - - await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, UseActionTypesResponse>(() => - useActionTypes() - ); - await waitForNextUpdate(); - await waitForNextUpdate(); - - expect(result.current).toEqual({ - loading: false, - actionTypes: [], - refetchActionTypes: result.current.refetchActionTypes, - }); - }); - }); -}); diff --git a/x-pack/plugins/cases/public/containers/configure/use_action_types.tsx b/x-pack/plugins/cases/public/containers/configure/use_action_types.tsx deleted file mode 100644 index 206952661e67..000000000000 --- a/x-pack/plugins/cases/public/containers/configure/use_action_types.tsx +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { useState, useEffect, useCallback, useRef } from 'react'; - -import { useStateToaster, errorToToaster } from '../../components/toasters'; -import * as i18n from '../translations'; -import { fetchActionTypes } from './api'; -import { ActionTypeConnector } from './types'; - -export interface UseActionTypesResponse { - loading: boolean; - actionTypes: ActionTypeConnector[]; - refetchActionTypes: () => void; -} - -export const useActionTypes = (): UseActionTypesResponse => { - const [, dispatchToaster] = useStateToaster(); - const [loading, setLoading] = useState(true); - const [actionTypes, setActionTypes] = useState<ActionTypeConnector[]>([]); - const isCancelledRef = useRef(false); - const abortCtrlRef = useRef(new AbortController()); - const queryFirstTime = useRef(true); - - const refetchActionTypes = useCallback(async () => { - try { - setLoading(true); - isCancelledRef.current = false; - abortCtrlRef.current.abort(); - abortCtrlRef.current = new AbortController(); - - const res = await fetchActionTypes({ signal: abortCtrlRef.current.signal }); - - if (!isCancelledRef.current) { - setLoading(false); - setActionTypes(res); - } - } catch (error) { - if (!isCancelledRef.current) { - setLoading(false); - setActionTypes([]); - errorToToaster({ - title: i18n.ERROR_TITLE, - error: error.body && error.body.message ? new Error(error.body.message) : error, - dispatchToaster, - }); - } - } - }, [dispatchToaster]); - - useEffect(() => { - if (queryFirstTime.current) { - refetchActionTypes(); - queryFirstTime.current = false; - } - - return () => { - isCancelledRef.current = true; - abortCtrlRef.current.abort(); - queryFirstTime.current = true; - }; - }, [refetchActionTypes]); - - return { - loading, - actionTypes, - refetchActionTypes, - }; -}; diff --git a/x-pack/plugins/cases/public/containers/configure/use_configure.test.tsx b/x-pack/plugins/cases/public/containers/configure/use_configure.test.tsx deleted file mode 100644 index 4e4db4cb5e82..000000000000 --- a/x-pack/plugins/cases/public/containers/configure/use_configure.test.tsx +++ /dev/null @@ -1,326 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { renderHook, act } from '@testing-library/react-hooks'; -import { - initialState, - useCaseConfigure, - ReturnUseCaseConfigure, - ConnectorConfiguration, -} from './use_configure'; -import { mappings, caseConfigurationCamelCaseResponseMock } from './mock'; -import * as api from './api'; -import { ConnectorTypes } from '../../../common'; - -jest.mock('./api'); -const mockErrorToToaster = jest.fn(); -jest.mock('../../components/toasters', () => { - const original = jest.requireActual('../../components/toasters'); - return { - ...original, - errorToToaster: () => mockErrorToToaster(), - }; -}); -const configuration: ConnectorConfiguration = { - connector: { - id: '456', - name: 'My connector 2', - type: ConnectorTypes.none, - fields: null, - }, - closureType: 'close-by-pushing', -}; - -describe('useConfigure', () => { - beforeEach(() => { - jest.clearAllMocks(); - jest.restoreAllMocks(); - }); - - test('init', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, ReturnUseCaseConfigure>(() => - useCaseConfigure() - ); - await waitForNextUpdate(); - expect(result.current).toEqual({ - ...initialState, - refetchCaseConfigure: result.current.refetchCaseConfigure, - persistCaseConfigure: result.current.persistCaseConfigure, - setCurrentConfiguration: result.current.setCurrentConfiguration, - setConnector: result.current.setConnector, - setClosureType: result.current.setClosureType, - setMappings: result.current.setMappings, - }); - }); - }); - - test('fetch case configuration', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, ReturnUseCaseConfigure>(() => - useCaseConfigure() - ); - await waitForNextUpdate(); - await waitForNextUpdate(); - expect(result.current).toEqual({ - ...initialState, - closureType: caseConfigurationCamelCaseResponseMock.closureType, - connector: caseConfigurationCamelCaseResponseMock.connector, - currentConfiguration: { - closureType: caseConfigurationCamelCaseResponseMock.closureType, - connector: caseConfigurationCamelCaseResponseMock.connector, - }, - mappings: [], - firstLoad: true, - loading: false, - persistCaseConfigure: result.current.persistCaseConfigure, - refetchCaseConfigure: result.current.refetchCaseConfigure, - setClosureType: result.current.setClosureType, - setConnector: result.current.setConnector, - setCurrentConfiguration: result.current.setCurrentConfiguration, - setMappings: result.current.setMappings, - version: caseConfigurationCamelCaseResponseMock.version, - }); - }); - }); - - test('refetch case configuration', async () => { - const spyOnGetCaseConfigure = jest.spyOn(api, 'getCaseConfigure'); - - await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, ReturnUseCaseConfigure>(() => - useCaseConfigure() - ); - await waitForNextUpdate(); - await waitForNextUpdate(); - result.current.refetchCaseConfigure(); - expect(spyOnGetCaseConfigure).toHaveBeenCalledTimes(2); - }); - }); - - test('correctly sets mappings', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, ReturnUseCaseConfigure>(() => - useCaseConfigure() - ); - await waitForNextUpdate(); - await waitForNextUpdate(); - expect(result.current.mappings).toEqual([]); - result.current.setMappings(mappings); - expect(result.current.mappings).toEqual(mappings); - }); - }); - - test('set isLoading to true when fetching case configuration', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, ReturnUseCaseConfigure>(() => - useCaseConfigure() - ); - await waitForNextUpdate(); - await waitForNextUpdate(); - result.current.refetchCaseConfigure(); - - expect(result.current.loading).toBe(true); - }); - }); - - test('persist case configuration', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, ReturnUseCaseConfigure>(() => - useCaseConfigure() - ); - await waitForNextUpdate(); - await waitForNextUpdate(); - result.current.persistCaseConfigure(configuration); - expect(result.current.persistLoading).toBeTruthy(); - }); - }); - - test('save case configuration - postCaseConfigure', async () => { - // When there is no version, a configuration is created. Otherwise is updated. - const spyOnGetCaseConfigure = jest.spyOn(api, 'getCaseConfigure'); - spyOnGetCaseConfigure.mockImplementation(() => - Promise.resolve({ - ...caseConfigurationCamelCaseResponseMock, - version: '', - }) - ); - - const spyOnPostCaseConfigure = jest.spyOn(api, 'postCaseConfigure'); - spyOnPostCaseConfigure.mockImplementation(() => - Promise.resolve({ - ...caseConfigurationCamelCaseResponseMock, - ...configuration, - }) - ); - - await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, ReturnUseCaseConfigure>(() => - useCaseConfigure() - ); - await waitForNextUpdate(); - await waitForNextUpdate(); - expect(mockErrorToToaster).not.toHaveBeenCalled(); - - result.current.persistCaseConfigure(configuration); - - expect(result.current.connector.id).toEqual('123'); - await waitForNextUpdate(); - expect(result.current.connector.id).toEqual('456'); - }); - }); - - test('Displays error when present - getCaseConfigure', async () => { - const spyOnGetCaseConfigure = jest.spyOn(api, 'getCaseConfigure'); - spyOnGetCaseConfigure.mockImplementation(() => - Promise.resolve({ - ...caseConfigurationCamelCaseResponseMock, - error: 'uh oh homeboy', - version: '', - }) - ); - - await act(async () => { - const { waitForNextUpdate } = renderHook<string, ReturnUseCaseConfigure>(() => - useCaseConfigure() - ); - await waitForNextUpdate(); - await waitForNextUpdate(); - expect(mockErrorToToaster).toHaveBeenCalled(); - }); - }); - - test('Displays error when present - postCaseConfigure', async () => { - // When there is no version, a configuration is created. Otherwise is updated. - const spyOnGetCaseConfigure = jest.spyOn(api, 'getCaseConfigure'); - spyOnGetCaseConfigure.mockImplementation(() => - Promise.resolve({ - ...caseConfigurationCamelCaseResponseMock, - version: '', - }) - ); - - const spyOnPostCaseConfigure = jest.spyOn(api, 'postCaseConfigure'); - spyOnPostCaseConfigure.mockImplementation(() => - Promise.resolve({ - ...caseConfigurationCamelCaseResponseMock, - ...configuration, - error: 'uh oh homeboy', - }) - ); - - await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, ReturnUseCaseConfigure>(() => - useCaseConfigure() - ); - await waitForNextUpdate(); - await waitForNextUpdate(); - expect(mockErrorToToaster).not.toHaveBeenCalled(); - - result.current.persistCaseConfigure(configuration); - expect(mockErrorToToaster).not.toHaveBeenCalled(); - await waitForNextUpdate(); - expect(mockErrorToToaster).toHaveBeenCalled(); - }); - }); - - test('save case configuration - patchCaseConfigure', async () => { - const spyOnPatchCaseConfigure = jest.spyOn(api, 'patchCaseConfigure'); - spyOnPatchCaseConfigure.mockImplementation(() => - Promise.resolve({ - ...caseConfigurationCamelCaseResponseMock, - ...configuration, - }) - ); - - await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, ReturnUseCaseConfigure>(() => - useCaseConfigure() - ); - await waitForNextUpdate(); - await waitForNextUpdate(); - - result.current.persistCaseConfigure(configuration); - - expect(result.current.connector.id).toEqual('123'); - await waitForNextUpdate(); - expect(result.current.connector.id).toEqual('456'); - }); - }); - - test('unhappy path - fetch case configuration', async () => { - const spyOnGetCaseConfigure = jest.spyOn(api, 'getCaseConfigure'); - spyOnGetCaseConfigure.mockImplementation(() => { - throw new Error('Something went wrong'); - }); - - await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, ReturnUseCaseConfigure>(() => - useCaseConfigure() - ); - - await waitForNextUpdate(); - await waitForNextUpdate(); - - expect(result.current).toEqual({ - ...initialState, - loading: false, - persistCaseConfigure: result.current.persistCaseConfigure, - persistLoading: false, - refetchCaseConfigure: result.current.refetchCaseConfigure, - setClosureType: result.current.setClosureType, - setConnector: result.current.setConnector, - setCurrentConfiguration: result.current.setCurrentConfiguration, - setMappings: result.current.setMappings, - }); - }); - }); - - test('unhappy path - persist case configuration', async () => { - const spyOnGetCaseConfigure = jest.spyOn(api, 'getCaseConfigure'); - spyOnGetCaseConfigure.mockImplementation(() => - Promise.resolve({ - ...caseConfigurationCamelCaseResponseMock, - version: '', - }) - ); - const spyOnPostCaseConfigure = jest.spyOn(api, 'postCaseConfigure'); - spyOnPostCaseConfigure.mockImplementation(() => { - throw new Error('Something went wrong'); - }); - - await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, ReturnUseCaseConfigure>(() => - useCaseConfigure() - ); - - await waitForNextUpdate(); - await waitForNextUpdate(); - - result.current.persistCaseConfigure(configuration); - - expect(result.current).toEqual({ - ...initialState, - closureType: caseConfigurationCamelCaseResponseMock.closureType, - connector: caseConfigurationCamelCaseResponseMock.connector, - currentConfiguration: { - closureType: caseConfigurationCamelCaseResponseMock.closureType, - connector: caseConfigurationCamelCaseResponseMock.connector, - }, - firstLoad: true, - loading: false, - mappings: [], - persistCaseConfigure: result.current.persistCaseConfigure, - refetchCaseConfigure: result.current.refetchCaseConfigure, - setClosureType: result.current.setClosureType, - setConnector: result.current.setConnector, - setCurrentConfiguration: result.current.setCurrentConfiguration, - setMappings: result.current.setMappings, - }); - }); - }); -}); diff --git a/x-pack/plugins/cases/public/containers/configure/use_configure.tsx b/x-pack/plugins/cases/public/containers/configure/use_configure.tsx deleted file mode 100644 index 3d5e43b2772a..000000000000 --- a/x-pack/plugins/cases/public/containers/configure/use_configure.tsx +++ /dev/null @@ -1,361 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { useEffect, useCallback, useReducer, useRef } from 'react'; -import { getCaseConfigure, patchCaseConfigure, postCaseConfigure } from './api'; - -import { useStateToaster, errorToToaster, displaySuccessToast } from '../../components/toasters'; -import * as i18n from './translations'; -import { ClosureType, CaseConfigure, CaseConnector, CaseConnectorMapping } from './types'; -import { ConnectorTypes } from '../../../common'; - -export type ConnectorConfiguration = { connector: CaseConnector } & { - closureType: CaseConfigure['closureType']; -}; - -export interface State extends ConnectorConfiguration { - currentConfiguration: ConnectorConfiguration; - firstLoad: boolean; - loading: boolean; - mappings: CaseConnectorMapping[]; - persistLoading: boolean; - version: string; -} -export type Action = - | { - type: 'setCurrentConfiguration'; - currentConfiguration: ConnectorConfiguration; - } - | { - type: 'setConnector'; - connector: CaseConnector; - } - | { - type: 'setLoading'; - payload: boolean; - } - | { - type: 'setFirstLoad'; - payload: boolean; - } - | { - type: 'setPersistLoading'; - payload: boolean; - } - | { - type: 'setVersion'; - payload: string; - } - | { - type: 'setClosureType'; - closureType: ClosureType; - } - | { - type: 'setMappings'; - mappings: CaseConnectorMapping[]; - }; - -export const configureCasesReducer = (state: State, action: Action) => { - switch (action.type) { - case 'setLoading': - return { - ...state, - loading: action.payload, - }; - case 'setFirstLoad': - return { - ...state, - firstLoad: action.payload, - }; - case 'setPersistLoading': - return { - ...state, - persistLoading: action.payload, - }; - case 'setVersion': - return { - ...state, - version: action.payload, - }; - case 'setCurrentConfiguration': { - return { - ...state, - currentConfiguration: { ...action.currentConfiguration }, - }; - } - case 'setConnector': { - return { - ...state, - connector: action.connector, - }; - } - case 'setClosureType': { - return { - ...state, - closureType: action.closureType, - }; - } - case 'setMappings': { - return { - ...state, - mappings: action.mappings, - }; - } - default: - return state; - } -}; - -export interface ReturnUseCaseConfigure extends State { - persistCaseConfigure: ({ connector, closureType }: ConnectorConfiguration) => unknown; - refetchCaseConfigure: () => void; - setClosureType: (closureType: ClosureType) => void; - setConnector: (connector: CaseConnector) => void; - setCurrentConfiguration: (configuration: ConnectorConfiguration) => void; - setMappings: (newMapping: CaseConnectorMapping[]) => void; -} - -export const initialState: State = { - closureType: 'close-by-user', - connector: { - fields: null, - id: 'none', - name: 'none', - type: ConnectorTypes.none, - }, - currentConfiguration: { - closureType: 'close-by-user', - connector: { - fields: null, - id: 'none', - name: 'none', - type: ConnectorTypes.none, - }, - }, - firstLoad: false, - loading: true, - mappings: [], - persistLoading: false, - version: '', -}; - -export const useCaseConfigure = (): ReturnUseCaseConfigure => { - const [state, dispatch] = useReducer(configureCasesReducer, initialState); - - const setCurrentConfiguration = useCallback((configuration: ConnectorConfiguration) => { - dispatch({ - currentConfiguration: configuration, - type: 'setCurrentConfiguration', - }); - }, []); - - const setConnector = useCallback((connector: CaseConnector) => { - dispatch({ - connector, - type: 'setConnector', - }); - }, []); - - const setClosureType = useCallback((closureType: ClosureType) => { - dispatch({ - closureType, - type: 'setClosureType', - }); - }, []); - - const setMappings = useCallback((mappings: CaseConnectorMapping[]) => { - dispatch({ - mappings, - type: 'setMappings', - }); - }, []); - - const setLoading = useCallback((isLoading: boolean) => { - dispatch({ - payload: isLoading, - type: 'setLoading', - }); - }, []); - - const setFirstLoad = useCallback((isFirstLoad: boolean) => { - dispatch({ - payload: isFirstLoad, - type: 'setFirstLoad', - }); - }, []); - - const setPersistLoading = useCallback((isPersistLoading: boolean) => { - dispatch({ - payload: isPersistLoading, - type: 'setPersistLoading', - }); - }, []); - - const setVersion = useCallback((version: string) => { - dispatch({ - payload: version, - type: 'setVersion', - }); - }, []); - - const [, dispatchToaster] = useStateToaster(); - const isCancelledRefetchRef = useRef(false); - const abortCtrlRefetchRef = useRef(new AbortController()); - - const isCancelledPersistRef = useRef(false); - const abortCtrlPersistRef = useRef(new AbortController()); - - const refetchCaseConfigure = useCallback(async () => { - try { - isCancelledRefetchRef.current = false; - abortCtrlRefetchRef.current.abort(); - abortCtrlRefetchRef.current = new AbortController(); - - setLoading(true); - const res = await getCaseConfigure({ signal: abortCtrlRefetchRef.current.signal }); - - if (!isCancelledRefetchRef.current) { - if (res != null) { - setConnector(res.connector); - if (setClosureType != null) { - setClosureType(res.closureType); - } - setVersion(res.version); - setMappings(res.mappings); - - if (!state.firstLoad) { - setFirstLoad(true); - if (setCurrentConfiguration != null) { - setCurrentConfiguration({ - closureType: res.closureType, - connector: { - ...res.connector, - }, - }); - } - } - if (res.error != null) { - errorToToaster({ - dispatchToaster, - error: new Error(res.error), - title: i18n.ERROR_TITLE, - }); - } - } - setLoading(false); - } - } catch (error) { - if (!isCancelledRefetchRef.current) { - if (error.name !== 'AbortError') { - errorToToaster({ - dispatchToaster, - error: error.body && error.body.message ? new Error(error.body.message) : error, - title: i18n.ERROR_TITLE, - }); - } - setLoading(false); - } - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [state.firstLoad]); - - const persistCaseConfigure = useCallback( - async ({ connector, closureType }: ConnectorConfiguration) => { - try { - isCancelledPersistRef.current = false; - abortCtrlPersistRef.current.abort(); - abortCtrlPersistRef.current = new AbortController(); - setPersistLoading(true); - - const connectorObj = { - connector, - closure_type: closureType, - }; - - const res = - state.version.length === 0 - ? await postCaseConfigure(connectorObj, abortCtrlPersistRef.current.signal) - : await patchCaseConfigure( - { - ...connectorObj, - version: state.version, - }, - abortCtrlPersistRef.current.signal - ); - - if (!isCancelledPersistRef.current) { - setConnector(res.connector); - if (setClosureType) { - setClosureType(res.closureType); - } - setVersion(res.version); - setMappings(res.mappings); - if (setCurrentConfiguration != null) { - setCurrentConfiguration({ - closureType: res.closureType, - connector: { - ...res.connector, - }, - }); - } - if (res.error != null) { - errorToToaster({ - dispatchToaster, - error: new Error(res.error), - title: i18n.ERROR_TITLE, - }); - } - displaySuccessToast(i18n.SUCCESS_CONFIGURE, dispatchToaster); - setPersistLoading(false); - } - } catch (error) { - if (!isCancelledPersistRef.current) { - if (error.name !== 'AbortError') { - errorToToaster({ - title: i18n.ERROR_TITLE, - error: error.body && error.body.message ? new Error(error.body.message) : error, - dispatchToaster, - }); - } - setConnector(state.currentConfiguration.connector); - setPersistLoading(false); - } - } - }, - [ - dispatchToaster, - setClosureType, - setConnector, - setCurrentConfiguration, - setMappings, - setPersistLoading, - setVersion, - state, - ] - ); - - useEffect(() => { - refetchCaseConfigure(); - return () => { - isCancelledRefetchRef.current = true; - abortCtrlRefetchRef.current.abort(); - isCancelledPersistRef.current = true; - abortCtrlPersistRef.current.abort(); - }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - return { - ...state, - refetchCaseConfigure, - persistCaseConfigure, - setCurrentConfiguration, - setConnector, - setClosureType, - setMappings, - }; -}; diff --git a/x-pack/plugins/cases/public/containers/configure/use_connectors.test.tsx b/x-pack/plugins/cases/public/containers/configure/use_connectors.test.tsx deleted file mode 100644 index ed1dfcbc40c8..000000000000 --- a/x-pack/plugins/cases/public/containers/configure/use_connectors.test.tsx +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { renderHook, act } from '@testing-library/react-hooks'; -import { useConnectors, UseConnectorsResponse } from './use_connectors'; -import { connectorsMock } from './mock'; -import * as api from './api'; - -jest.mock('./api'); - -describe('useConnectors', () => { - beforeEach(() => { - jest.clearAllMocks(); - jest.restoreAllMocks(); - }); - - test('init', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, UseConnectorsResponse>(() => - useConnectors() - ); - await waitForNextUpdate(); - expect(result.current).toEqual({ - loading: true, - connectors: [], - refetchConnectors: result.current.refetchConnectors, - }); - }); - }); - - test('fetch connectors', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, UseConnectorsResponse>(() => - useConnectors() - ); - await waitForNextUpdate(); - await waitForNextUpdate(); - expect(result.current).toEqual({ - loading: false, - connectors: connectorsMock, - refetchConnectors: result.current.refetchConnectors, - }); - }); - }); - - test('refetch connectors', async () => { - const spyOnfetchConnectors = jest.spyOn(api, 'fetchConnectors'); - await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, UseConnectorsResponse>(() => - useConnectors() - ); - await waitForNextUpdate(); - await waitForNextUpdate(); - result.current.refetchConnectors(); - expect(spyOnfetchConnectors).toHaveBeenCalledTimes(2); - }); - }); - - test('set isLoading to true when refetching connectors', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, UseConnectorsResponse>(() => - useConnectors() - ); - await waitForNextUpdate(); - await waitForNextUpdate(); - result.current.refetchConnectors(); - - expect(result.current.loading).toBe(true); - }); - }); - - test('unhappy path', async () => { - const spyOnfetchConnectors = jest.spyOn(api, 'fetchConnectors'); - spyOnfetchConnectors.mockImplementation(() => { - throw new Error('Something went wrong'); - }); - - await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, UseConnectorsResponse>(() => - useConnectors() - ); - await waitForNextUpdate(); - await waitForNextUpdate(); - - expect(result.current).toEqual({ - loading: false, - connectors: [], - refetchConnectors: result.current.refetchConnectors, - }); - }); - }); -}); diff --git a/x-pack/plugins/cases/public/containers/configure/use_connectors.tsx b/x-pack/plugins/cases/public/containers/configure/use_connectors.tsx deleted file mode 100644 index b385a2676e04..000000000000 --- a/x-pack/plugins/cases/public/containers/configure/use_connectors.tsx +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { useState, useEffect, useCallback, useRef } from 'react'; - -import { useStateToaster, errorToToaster } from '../../components/toasters'; -import * as i18n from '../translations'; -import { fetchConnectors } from './api'; -import { ActionConnector } from './types'; - -export interface UseConnectorsResponse { - loading: boolean; - connectors: ActionConnector[]; - refetchConnectors: () => void; -} - -export const useConnectors = (): UseConnectorsResponse => { - const [, dispatchToaster] = useStateToaster(); - const [loading, setLoading] = useState(true); - const [connectors, setConnectors] = useState<ActionConnector[]>([]); - const isCancelledRef = useRef(false); - const abortCtrlRef = useRef(new AbortController()); - - const refetchConnectors = useCallback(async () => { - try { - isCancelledRef.current = false; - abortCtrlRef.current.abort(); - abortCtrlRef.current = new AbortController(); - - setLoading(true); - const res = await fetchConnectors({ signal: abortCtrlRef.current.signal }); - - if (!isCancelledRef.current) { - setLoading(false); - setConnectors(res); - } - } catch (error) { - if (!isCancelledRef.current) { - if (error.name !== 'AbortError') { - errorToToaster({ - title: i18n.ERROR_TITLE, - error: error.body && error.body.message ? new Error(error.body.message) : error, - dispatchToaster, - }); - } - - setLoading(false); - setConnectors([]); - } - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - useEffect(() => { - refetchConnectors(); - return () => { - isCancelledRef.current = true; - abortCtrlRef.current.abort(); - }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - return { - loading, - connectors, - refetchConnectors, - }; -}; diff --git a/x-pack/plugins/cases/public/containers/constants.ts b/x-pack/plugins/cases/public/containers/constants.ts deleted file mode 100644 index be030f4d2f75..000000000000 --- a/x-pack/plugins/cases/public/containers/constants.ts +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export const DEFAULT_TABLE_ACTIVE_PAGE = 1; -export const DEFAULT_TABLE_LIMIT = 5; diff --git a/x-pack/plugins/cases/public/containers/mock.ts b/x-pack/plugins/cases/public/containers/mock.ts deleted file mode 100644 index 1e7cec29de56..000000000000 --- a/x-pack/plugins/cases/public/containers/mock.ts +++ /dev/null @@ -1,377 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { ActionLicense, AllCases, Case, CasesStatus, CaseUserActions, Comment } from './types'; - -import { - AssociationType, - CaseResponse, - CasesFindResponse, - CasesResponse, - CasesStatusResponse, - CaseStatuses, - CaseType, - CaseUserActionsResponse, - CommentResponse, - CommentType, - ConnectorTypes, - UserAction, - UserActionField, -} from '../../common'; -import { UseGetCasesState, DEFAULT_FILTER_OPTIONS, DEFAULT_QUERY_PARAMS } from './use_get_cases'; -export { connectorsMock } from './configure/mock'; - -export const basicCaseId = 'basic-case-id'; -export const basicSubCaseId = 'basic-sub-case-id'; -const basicCommentId = 'basic-comment-id'; -const basicCreatedAt = '2020-02-19T23:06:33.798Z'; -const basicUpdatedAt = '2020-02-20T15:02:57.995Z'; -const laterTime = '2020-02-28T15:02:57.995Z'; - -export const elasticUser = { - fullName: 'Leslie Knope', - username: 'lknope', - email: 'leslie.knope@elastic.co', -}; - -export const tags: string[] = ['coke', 'pepsi']; - -export const basicComment: Comment = { - associationType: AssociationType.case, - comment: 'Solve this fast!', - type: CommentType.user, - id: basicCommentId, - createdAt: basicCreatedAt, - createdBy: elasticUser, - pushedAt: null, - pushedBy: null, - updatedAt: null, - updatedBy: null, - version: 'WzQ3LDFc', -}; - -export const alertComment: Comment = { - alertId: 'alert-id-1', - associationType: AssociationType.case, - index: 'alert-index-1', - type: CommentType.alert, - id: 'alert-comment-id', - createdAt: basicCreatedAt, - createdBy: elasticUser, - pushedAt: null, - pushedBy: null, - rule: { - id: 'rule-id-1', - name: 'Awesome rule', - }, - updatedAt: null, - updatedBy: null, - version: 'WzQ3LDFc', -}; - -export const basicCase: Case = { - type: CaseType.individual, - closedAt: null, - closedBy: null, - id: basicCaseId, - comments: [basicComment], - createdAt: basicCreatedAt, - createdBy: elasticUser, - connector: { - id: '123', - name: 'My Connector', - type: ConnectorTypes.none, - fields: null, - }, - description: 'Security banana Issue', - externalService: null, - status: CaseStatuses.open, - tags, - title: 'Another horrible breach!!', - totalComment: 1, - totalAlerts: 0, - updatedAt: basicUpdatedAt, - updatedBy: elasticUser, - version: 'WzQ3LDFd', - settings: { - syncAlerts: true, - }, - subCaseIds: [], -}; - -export const collectionCase: Case = { - type: CaseType.collection, - closedAt: null, - closedBy: null, - id: 'collection-id', - comments: [basicComment], - createdAt: basicCreatedAt, - createdBy: elasticUser, - connector: { - id: '123', - name: 'My Connector', - type: ConnectorTypes.none, - fields: null, - }, - description: 'Security banana Issue', - externalService: null, - status: CaseStatuses.open, - tags, - title: 'Another horrible breach in a collection!!', - totalComment: 1, - totalAlerts: 0, - updatedAt: basicUpdatedAt, - updatedBy: elasticUser, - version: 'WzQ3LDFd', - settings: { - syncAlerts: true, - }, - subCases: [], - subCaseIds: [], -}; - -export const basicCasePost: Case = { - ...basicCase, - updatedAt: null, - updatedBy: null, -}; - -export const basicCommentPatch: Comment = { - ...basicComment, - updatedAt: basicUpdatedAt, - updatedBy: { - username: 'elastic', - }, -}; - -export const basicCaseCommentPatch = { - ...basicCase, - comments: [basicCommentPatch], -}; - -export const casesStatus: CasesStatus = { - countOpenCases: 20, - countInProgressCases: 40, - countClosedCases: 130, -}; - -export const basicPush = { - connectorId: '123', - connectorName: 'connector name', - externalId: 'external_id', - externalTitle: 'external title', - externalUrl: 'basicPush.com', - pushedAt: basicUpdatedAt, - pushedBy: elasticUser, -}; - -export const pushedCase: Case = { - ...basicCase, - externalService: basicPush, -}; - -const basicAction = { - actionAt: basicCreatedAt, - actionBy: elasticUser, - oldValue: null, - newValue: 'what a cool value', - caseId: basicCaseId, - commentId: null, -}; - -export const cases: Case[] = [ - basicCase, - { ...pushedCase, id: '1', totalComment: 0, comments: [] }, - { ...pushedCase, updatedAt: laterTime, id: '2', totalComment: 0, comments: [] }, - { ...basicCase, id: '3', totalComment: 0, comments: [] }, - { ...basicCase, id: '4', totalComment: 0, comments: [] }, -]; - -export const allCases: AllCases = { - cases, - page: 1, - perPage: 5, - total: 10, - ...casesStatus, -}; - -export const actionLicenses: ActionLicense[] = [ - { - id: '.servicenow', - name: 'ServiceNow', - enabled: true, - enabledInConfig: true, - enabledInLicense: true, - }, - { - id: '.jira', - name: 'Jira', - enabled: true, - enabledInConfig: true, - enabledInLicense: true, - }, -]; - -// Snake case for mock api responses -export const elasticUserSnake = { - full_name: 'Leslie Knope', - username: 'lknope', - email: 'leslie.knope@elastic.co', -}; - -export const basicCommentSnake: CommentResponse = { - associationType: AssociationType.case, - comment: 'Solve this fast!', - type: CommentType.user, - id: basicCommentId, - created_at: basicCreatedAt, - created_by: elasticUserSnake, - pushed_at: null, - pushed_by: null, - updated_at: null, - updated_by: null, - version: 'WzQ3LDFc', -}; - -export const basicCaseSnake: CaseResponse = { - ...basicCase, - status: CaseStatuses.open, - closed_at: null, - closed_by: null, - comments: [basicCommentSnake], - connector: { - id: '123', - name: 'My Connector', - type: ConnectorTypes.none, - fields: null, - }, - created_at: basicCreatedAt, - created_by: elasticUserSnake, - external_service: null, - updated_at: basicUpdatedAt, - updated_by: elasticUserSnake, -} as CaseResponse; - -export const casesStatusSnake: CasesStatusResponse = { - count_closed_cases: 130, - count_in_progress_cases: 40, - count_open_cases: 20, -}; - -export const pushSnake = { - connector_id: '123', - connector_name: 'connector name', - external_id: 'external_id', - external_title: 'external title', - external_url: 'basicPush.com', -}; - -export const basicPushSnake = { - ...pushSnake, - pushed_at: basicUpdatedAt, - pushed_by: elasticUserSnake, -}; - -export const pushedCaseSnake = { - ...basicCaseSnake, - external_service: basicPushSnake, -}; - -export const reporters: string[] = ['alexis', 'kim', 'maria', 'steph']; -export const respReporters = [ - { username: 'alexis', full_name: null, email: null }, - { username: 'kim', full_name: null, email: null }, - { username: 'maria', full_name: null, email: null }, - { username: 'steph', full_name: null, email: null }, -]; -export const casesSnake: CasesResponse = [ - basicCaseSnake, - { ...pushedCaseSnake, id: '1', totalComment: 0, comments: [] }, - { ...pushedCaseSnake, updated_at: laterTime, id: '2', totalComment: 0, comments: [] }, - { ...basicCaseSnake, id: '3', totalComment: 0, comments: [] }, - { ...basicCaseSnake, id: '4', totalComment: 0, comments: [] }, -]; - -export const allCasesSnake: CasesFindResponse = { - cases: casesSnake, - page: 1, - per_page: 5, - total: 10, - ...casesStatusSnake, -}; - -const basicActionSnake = { - action_at: basicCreatedAt, - action_by: elasticUserSnake, - old_value: null, - new_value: 'what a cool value', - case_id: basicCaseId, - comment_id: null, -}; -export const getUserActionSnake = (af: UserActionField, a: UserAction) => ({ - ...basicActionSnake, - action_id: `${af[0]}-${a}`, - action_field: af, - action: a, - comment_id: af[0] === 'comment' ? basicCommentId : null, - new_value: - a === 'push-to-service' && af[0] === 'pushed' - ? JSON.stringify(basicPushSnake) - : basicAction.newValue, -}); - -export const caseUserActionsSnake: CaseUserActionsResponse = [ - getUserActionSnake(['description'], 'create'), - getUserActionSnake(['comment'], 'create'), - getUserActionSnake(['description'], 'update'), -]; - -// user actions - -export const getUserAction = (af: UserActionField, a: UserAction) => ({ - ...basicAction, - actionId: `${af[0]}-${a}`, - actionField: af, - action: a, - commentId: af[0] === 'comment' ? basicCommentId : null, - newValue: - a === 'push-to-service' && af[0] === 'pushed' - ? JSON.stringify(basicPushSnake) - : basicAction.newValue, -}); - -export const getAlertUserAction = () => ({ - ...basicAction, - actionId: 'alert-action-id', - actionField: ['comment'], - action: 'create', - commentId: 'alert-comment-id', - newValue: '{"type":"alert","alertId":"alert-id-1","index":"index-id-1"}', -}); - -export const caseUserActions: CaseUserActions[] = [ - getUserAction(['description'], 'create'), - getUserAction(['comment'], 'create'), - getUserAction(['description'], 'update'), -]; - -// components tests -export const useGetCasesMockState: UseGetCasesState = { - data: allCases, - loading: [], - selectedCases: [], - isError: false, - queryParams: DEFAULT_QUERY_PARAMS, - filterOptions: DEFAULT_FILTER_OPTIONS, -}; - -export const basicCaseClosed: Case = { - ...basicCase, - closedAt: '2020-02-25T23:06:33.798Z', - closedBy: elasticUser, - status: CaseStatuses.closed, -}; diff --git a/x-pack/plugins/cases/public/containers/translations.ts b/x-pack/plugins/cases/public/containers/translations.ts deleted file mode 100644 index 966a5e158923..000000000000 --- a/x-pack/plugins/cases/public/containers/translations.ts +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; - -export * from '../common/translations'; - -export const ERROR_TITLE = i18n.translate('xpack.cases.containers.errorTitle', { - defaultMessage: 'Error fetching data', -}); - -export const ERROR_DELETING = i18n.translate('xpack.cases.containers.errorDeletingTitle', { - defaultMessage: 'Error deleting data', -}); - -export const UPDATED_CASE = (caseTitle: string) => - i18n.translate('xpack.cases.containers.updatedCase', { - values: { caseTitle }, - defaultMessage: 'Updated "{caseTitle}"', - }); - -export const DELETED_CASES = (totalCases: number, caseTitle?: string) => - i18n.translate('xpack.cases.containers.deletedCases', { - values: { caseTitle, totalCases }, - defaultMessage: 'Deleted {totalCases, plural, =1 {"{caseTitle}"} other {{totalCases} cases}}', - }); - -export const CLOSED_CASES = ({ - totalCases, - caseTitle, -}: { - totalCases: number; - caseTitle?: string; -}) => - i18n.translate('xpack.cases.containers.closedCases', { - values: { caseTitle, totalCases }, - defaultMessage: 'Closed {totalCases, plural, =1 {"{caseTitle}"} other {{totalCases} cases}}', - }); - -export const REOPENED_CASES = ({ - totalCases, - caseTitle, -}: { - totalCases: number; - caseTitle?: string; -}) => - i18n.translate('xpack.cases.containers.reopenedCases', { - values: { caseTitle, totalCases }, - defaultMessage: 'Opened {totalCases, plural, =1 {"{caseTitle}"} other {{totalCases} cases}}', - }); - -export const MARK_IN_PROGRESS_CASES = ({ - totalCases, - caseTitle, -}: { - totalCases: number; - caseTitle?: string; -}) => - i18n.translate('xpack.cases.containers.markInProgressCases', { - values: { caseTitle, totalCases }, - defaultMessage: - 'Marked {totalCases, plural, =1 {"{caseTitle}"} other {{totalCases} cases}} as in progress', - }); - -export const SUCCESS_SEND_TO_EXTERNAL_SERVICE = (serviceName: string) => - i18n.translate('xpack.cases.containers.pushToExternalService', { - values: { serviceName }, - 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 }, - defaultMessage: 'Alerts in "{caseTitle}" have been synced', - }); - -export const STATUS_CHANGED_TOASTER_TEXT = i18n.translate( - 'xpack.cases.containers.statusChangeToasterText', - { - defaultMessage: 'Alerts in this case have been also had their status updated', - } -); diff --git a/x-pack/plugins/cases/public/containers/types.ts b/x-pack/plugins/cases/public/containers/types.ts deleted file mode 100644 index db6c6e678d18..000000000000 --- a/x-pack/plugins/cases/public/containers/types.ts +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - User, - UserActionField, - UserAction, - CaseConnector, - CommentRequest, - CaseStatuses, - CaseAttributes, - CasePatchRequest, - CaseType, - AssociationType, -} from '../../common'; -import { CaseStatusWithAllStatus } from '../components/status'; - -export { CaseConnector, ActionConnector, CaseStatuses } from '../../common'; - -export type Comment = CommentRequest & { - associationType: AssociationType; - id: string; - createdAt: string; - createdBy: ElasticUser; - pushedAt: string | null; - pushedBy: string | null; - updatedAt: string | null; - updatedBy: ElasticUser | null; - version: string; -}; -export interface CaseUserActions { - actionId: string; - actionField: UserActionField; - action: UserAction; - actionAt: string; - actionBy: ElasticUser; - caseId: string; - commentId: string | null; - newValue: string | null; - oldValue: string | null; -} - -export interface CaseExternalService { - pushedAt: string; - pushedBy: ElasticUser; - connectorId: string; - connectorName: string; - externalId: string; - externalTitle: string; - externalUrl: string; -} - -interface BasicCase { - id: string; - closedAt: string | null; - closedBy: ElasticUser | null; - comments: Comment[]; - createdAt: string; - createdBy: ElasticUser; - status: CaseStatuses; - title: string; - totalAlerts: number; - totalComment: number; - updatedAt: string | null; - updatedBy: ElasticUser | null; - version: string; -} - -export interface SubCase extends BasicCase { - associationType: AssociationType; - caseParentId: string; -} - -export interface Case extends BasicCase { - connector: CaseConnector; - description: string; - externalService: CaseExternalService | null; - subCases?: SubCase[] | null; - subCaseIds: string[]; - settings: CaseAttributes['settings']; - tags: string[]; - type: CaseType; -} - -export interface QueryParams { - page: number; - perPage: number; - sortField: SortFieldCase; - sortOrder: 'asc' | 'desc'; -} - -export interface FilterOptions { - search: string; - status: CaseStatusWithAllStatus; - tags: string[]; - reporters: User[]; - onlyCollectionType?: boolean; -} - -export interface CasesStatus { - countClosedCases: number | null; - countOpenCases: number | null; - countInProgressCases: number | null; -} - -export interface AllCases extends CasesStatus { - cases: Case[]; - page: number; - perPage: number; - total: number; -} - -export enum SortFieldCase { - createdAt = 'createdAt', - closedAt = 'closedAt', - updatedAt = 'updatedAt', -} - -export interface ElasticUser { - readonly email?: string | null; - readonly fullName?: string | null; - readonly username?: string | null; -} - -export interface FetchCasesProps extends ApiProps { - queryParams?: QueryParams; - filterOptions?: FilterOptions; -} - -export interface ApiProps { - signal: AbortSignal; -} - -export interface BulkUpdateStatus { - status: string; - id: string; - version: string; -} -export interface ActionLicense { - id: string; - name: string; - enabled: boolean; - enabledInConfig: boolean; - enabledInLicense: boolean; -} - -export interface DeleteCase { - id: string; - type: CaseType | null; - title?: string; -} - -export interface FieldMappings { - id: string; - title?: string; -} - -export type UpdateKey = keyof Pick< - CasePatchRequest, - 'connector' | 'description' | 'status' | 'tags' | 'title' | 'settings' ->; - -export interface UpdateByKey { - updateKey: UpdateKey; - updateValue: CasePatchRequest[UpdateKey]; - fetchCaseUserActions?: (caseId: string, caseConnectorId: string, subCaseId?: string) => void; - updateCase?: (newCase: Case) => void; - caseData: Case; - onSuccess?: () => void; - onError?: () => void; -} diff --git a/x-pack/plugins/cases/public/containers/use_get_cases.test.tsx b/x-pack/plugins/cases/public/containers/use_get_cases.test.tsx deleted file mode 100644 index 8b5993255552..000000000000 --- a/x-pack/plugins/cases/public/containers/use_get_cases.test.tsx +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { renderHook, act } from '@testing-library/react-hooks'; -import { CaseStatuses } from '../../common'; -import { - DEFAULT_FILTER_OPTIONS, - DEFAULT_QUERY_PARAMS, - initialData, - useGetCases, - UseGetCases, -} from './use_get_cases'; -import { UpdateKey } from './types'; -import { allCases, basicCase } from './mock'; -import * as api from './api'; - -jest.mock('./api'); - -describe('useGetCases', () => { - const abortCtrl = new AbortController(); - beforeEach(() => { - jest.clearAllMocks(); - jest.restoreAllMocks(); - }); - - it('init', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, UseGetCases>(() => useGetCases()); - await waitForNextUpdate(); - expect(result.current).toEqual({ - data: initialData, - dispatchUpdateCaseProperty: result.current.dispatchUpdateCaseProperty, - filterOptions: DEFAULT_FILTER_OPTIONS, - isError: false, - loading: [], - queryParams: DEFAULT_QUERY_PARAMS, - refetchCases: result.current.refetchCases, - selectedCases: [], - setFilters: result.current.setFilters, - setQueryParams: result.current.setQueryParams, - setSelectedCases: result.current.setSelectedCases, - }); - }); - }); - - it('calls getCases with correct arguments', async () => { - const spyOnGetCases = jest.spyOn(api, 'getCases'); - await act(async () => { - const { waitForNextUpdate } = renderHook<string, UseGetCases>(() => useGetCases()); - await waitForNextUpdate(); - await waitForNextUpdate(); - expect(spyOnGetCases).toBeCalledWith({ - filterOptions: DEFAULT_FILTER_OPTIONS, - queryParams: DEFAULT_QUERY_PARAMS, - signal: abortCtrl.signal, - }); - }); - }); - - it('fetch cases', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, UseGetCases>(() => useGetCases()); - await waitForNextUpdate(); - await waitForNextUpdate(); - expect(result.current).toEqual({ - data: allCases, - dispatchUpdateCaseProperty: result.current.dispatchUpdateCaseProperty, - filterOptions: DEFAULT_FILTER_OPTIONS, - isError: false, - loading: [], - queryParams: DEFAULT_QUERY_PARAMS, - refetchCases: result.current.refetchCases, - selectedCases: [], - setFilters: result.current.setFilters, - setQueryParams: result.current.setQueryParams, - setSelectedCases: result.current.setSelectedCases, - }); - }); - }); - it('dispatch update case property', async () => { - const spyOnPatchCase = jest.spyOn(api, 'patchCase'); - await act(async () => { - const updateCase = { - updateKey: 'description' as UpdateKey, - updateValue: 'description update', - caseId: basicCase.id, - refetchCasesStatus: jest.fn(), - version: '99999', - }; - const { result, waitForNextUpdate } = renderHook<string, UseGetCases>(() => useGetCases()); - await waitForNextUpdate(); - await waitForNextUpdate(); - result.current.dispatchUpdateCaseProperty(updateCase); - expect(result.current.loading).toEqual(['caseUpdate']); - expect(spyOnPatchCase).toBeCalledWith( - basicCase.id, - { [updateCase.updateKey]: updateCase.updateValue }, - updateCase.version, - abortCtrl.signal - ); - }); - }); - - it('refetch cases', async () => { - const spyOnGetCases = jest.spyOn(api, 'getCases'); - await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, UseGetCases>(() => useGetCases()); - await waitForNextUpdate(); - await waitForNextUpdate(); - result.current.refetchCases(); - expect(spyOnGetCases).toHaveBeenCalledTimes(2); - }); - }); - - it('set isLoading to true when refetching case', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, UseGetCases>(() => useGetCases()); - await waitForNextUpdate(); - await waitForNextUpdate(); - result.current.refetchCases(); - - expect(result.current.loading).toEqual(['cases']); - }); - }); - - it('unhappy path', async () => { - const spyOnGetCases = jest.spyOn(api, 'getCases'); - spyOnGetCases.mockImplementation(() => { - throw new Error('Something went wrong'); - }); - - await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, UseGetCases>(() => useGetCases()); - await waitForNextUpdate(); - await waitForNextUpdate(); - - expect(result.current).toEqual({ - data: initialData, - dispatchUpdateCaseProperty: result.current.dispatchUpdateCaseProperty, - filterOptions: DEFAULT_FILTER_OPTIONS, - isError: true, - loading: [], - queryParams: DEFAULT_QUERY_PARAMS, - refetchCases: result.current.refetchCases, - selectedCases: [], - setFilters: result.current.setFilters, - setQueryParams: result.current.setQueryParams, - setSelectedCases: result.current.setSelectedCases, - }); - }); - }); - it('set filters', async () => { - await act(async () => { - const spyOnGetCases = jest.spyOn(api, 'getCases'); - const newFilters = { - search: 'new', - tags: ['new'], - status: CaseStatuses.closed, - }; - const { result, waitForNextUpdate } = renderHook<string, UseGetCases>(() => useGetCases()); - await waitForNextUpdate(); - await waitForNextUpdate(); - result.current.setFilters(newFilters); - await waitForNextUpdate(); - expect(spyOnGetCases.mock.calls[1][0]).toEqual({ - filterOptions: { ...DEFAULT_FILTER_OPTIONS, ...newFilters }, - queryParams: DEFAULT_QUERY_PARAMS, - signal: abortCtrl.signal, - }); - }); - }); - it('set query params', async () => { - await act(async () => { - const spyOnGetCases = jest.spyOn(api, 'getCases'); - const newQueryParams = { - page: 2, - }; - const { result, waitForNextUpdate } = renderHook<string, UseGetCases>(() => useGetCases()); - await waitForNextUpdate(); - await waitForNextUpdate(); - result.current.setQueryParams(newQueryParams); - await waitForNextUpdate(); - expect(spyOnGetCases.mock.calls[1][0]).toEqual({ - filterOptions: DEFAULT_FILTER_OPTIONS, - queryParams: { ...DEFAULT_QUERY_PARAMS, ...newQueryParams }, - signal: abortCtrl.signal, - }); - }); - }); - it('set selected cases', async () => { - await act(async () => { - const selectedCases = [basicCase]; - const { result, waitForNextUpdate } = renderHook<string, UseGetCases>(() => useGetCases()); - await waitForNextUpdate(); - await waitForNextUpdate(); - result.current.setSelectedCases(selectedCases); - expect(result.current.selectedCases).toEqual(selectedCases); - }); - }); -}); diff --git a/x-pack/plugins/cases/public/containers/use_get_cases.tsx b/x-pack/plugins/cases/public/containers/use_get_cases.tsx deleted file mode 100644 index e06a47954cdd..000000000000 --- a/x-pack/plugins/cases/public/containers/use_get_cases.tsx +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { useCallback, useEffect, useReducer, useRef } from 'react'; -import { DEFAULT_TABLE_ACTIVE_PAGE, DEFAULT_TABLE_LIMIT } from './constants'; -import { AllCases, SortFieldCase, FilterOptions, QueryParams, Case, UpdateByKey } from './types'; -import { errorToToaster, useStateToaster } from '../components/toasters'; -import * as i18n from './translations'; -import { getCases, patchCase } from './api'; -import { StatusAll } from '../components/status'; - -export interface UseGetCasesState { - data: AllCases; - filterOptions: FilterOptions; - isError: boolean; - loading: string[]; - queryParams: QueryParams; - selectedCases: Case[]; -} - -export interface UpdateCase extends Omit<UpdateByKey, 'caseData'> { - caseId: string; - version: string; - refetchCasesStatus: () => void; -} - -export type Action = - | { type: 'FETCH_INIT'; payload: string } - | { - type: 'FETCH_CASES_SUCCESS'; - payload: AllCases; - } - | { type: 'FETCH_FAILURE'; payload: string } - | { type: 'FETCH_UPDATE_CASE_SUCCESS' } - | { type: 'UPDATE_FILTER_OPTIONS'; payload: Partial<FilterOptions> } - | { type: 'UPDATE_QUERY_PARAMS'; payload: Partial<QueryParams> } - | { type: 'UPDATE_TABLE_SELECTIONS'; payload: Case[] }; - -const dataFetchReducer = (state: UseGetCasesState, action: Action): UseGetCasesState => { - switch (action.type) { - case 'FETCH_INIT': - return { - ...state, - isError: false, - loading: [...state.loading.filter((e) => e !== action.payload), action.payload], - }; - case 'FETCH_UPDATE_CASE_SUCCESS': - return { - ...state, - loading: state.loading.filter((e) => e !== 'caseUpdate'), - }; - case 'FETCH_CASES_SUCCESS': - return { - ...state, - data: action.payload, - isError: false, - loading: state.loading.filter((e) => e !== 'cases'), - }; - case 'FETCH_FAILURE': - return { - ...state, - isError: true, - loading: state.loading.filter((e) => e !== action.payload), - }; - case 'UPDATE_FILTER_OPTIONS': - return { - ...state, - filterOptions: { - ...state.filterOptions, - ...action.payload, - }, - }; - case 'UPDATE_QUERY_PARAMS': - return { - ...state, - queryParams: { - ...state.queryParams, - ...action.payload, - }, - }; - case 'UPDATE_TABLE_SELECTIONS': - return { - ...state, - selectedCases: action.payload, - }; - default: - return state; - } -}; - -export const DEFAULT_FILTER_OPTIONS: FilterOptions = { - search: '', - reporters: [], - status: StatusAll, - tags: [], - onlyCollectionType: false, -}; - -export const DEFAULT_QUERY_PARAMS: QueryParams = { - page: DEFAULT_TABLE_ACTIVE_PAGE, - perPage: DEFAULT_TABLE_LIMIT, - sortField: SortFieldCase.createdAt, - sortOrder: 'desc', -}; - -export const initialData: AllCases = { - cases: [], - countClosedCases: null, - countInProgressCases: null, - countOpenCases: null, - page: 0, - perPage: 0, - total: 0, -}; -export interface UseGetCases extends UseGetCasesState { - dispatchUpdateCaseProperty: ({ - updateKey, - updateValue, - caseId, - version, - refetchCasesStatus, - }: UpdateCase) => void; - refetchCases: () => void; - setFilters: (filters: Partial<FilterOptions>) => void; - setQueryParams: (queryParams: Partial<QueryParams>) => void; - setSelectedCases: (mySelectedCases: Case[]) => void; -} - -export const useGetCases = ( - initialQueryParams?: QueryParams, - initialFilterOptions?: FilterOptions -): UseGetCases => { - const [state, dispatch] = useReducer(dataFetchReducer, { - data: initialData, - filterOptions: initialFilterOptions ?? DEFAULT_FILTER_OPTIONS, - isError: false, - loading: [], - queryParams: initialQueryParams ?? DEFAULT_QUERY_PARAMS, - selectedCases: [], - }); - const [, dispatchToaster] = useStateToaster(); - const didCancelFetchCases = useRef(false); - const didCancelUpdateCases = useRef(false); - const abortCtrlFetchCases = useRef(new AbortController()); - const abortCtrlUpdateCases = useRef(new AbortController()); - - const setSelectedCases = useCallback((mySelectedCases: Case[]) => { - dispatch({ type: 'UPDATE_TABLE_SELECTIONS', payload: mySelectedCases }); - }, []); - - const setQueryParams = useCallback((newQueryParams: Partial<QueryParams>) => { - dispatch({ type: 'UPDATE_QUERY_PARAMS', payload: newQueryParams }); - }, []); - - const setFilters = useCallback((newFilters: Partial<FilterOptions>) => { - dispatch({ type: 'UPDATE_FILTER_OPTIONS', payload: newFilters }); - }, []); - - const fetchCases = useCallback(async (filterOptions: FilterOptions, queryParams: QueryParams) => { - try { - didCancelFetchCases.current = false; - abortCtrlFetchCases.current.abort(); - abortCtrlFetchCases.current = new AbortController(); - dispatch({ type: 'FETCH_INIT', payload: 'cases' }); - - const response = await getCases({ - filterOptions, - queryParams, - signal: abortCtrlFetchCases.current.signal, - }); - - if (!didCancelFetchCases.current) { - dispatch({ - type: 'FETCH_CASES_SUCCESS', - payload: response, - }); - } - } catch (error) { - if (!didCancelFetchCases.current) { - if (error.name !== 'AbortError') { - errorToToaster({ - title: i18n.ERROR_TITLE, - error: error.body && error.body.message ? new Error(error.body.message) : error, - dispatchToaster, - }); - } - dispatch({ type: 'FETCH_FAILURE', payload: 'cases' }); - } - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - const dispatchUpdateCaseProperty = useCallback( - async ({ updateKey, updateValue, caseId, refetchCasesStatus, version }: UpdateCase) => { - try { - didCancelUpdateCases.current = false; - abortCtrlUpdateCases.current.abort(); - abortCtrlUpdateCases.current = new AbortController(); - dispatch({ type: 'FETCH_INIT', payload: 'caseUpdate' }); - - await patchCase( - caseId, - { [updateKey]: updateValue }, - // saved object versions are typed as string | undefined, hope that's not true - version ?? '', - abortCtrlUpdateCases.current.signal - ); - - if (!didCancelUpdateCases.current) { - dispatch({ type: 'FETCH_UPDATE_CASE_SUCCESS' }); - fetchCases(state.filterOptions, state.queryParams); - refetchCasesStatus(); - } - } catch (error) { - if (!didCancelUpdateCases.current) { - if (error.name !== 'AbortError') { - errorToToaster({ title: i18n.ERROR_TITLE, error, dispatchToaster }); - } - dispatch({ type: 'FETCH_FAILURE', payload: 'caseUpdate' }); - } - } - }, - // eslint-disable-next-line react-hooks/exhaustive-deps - [state.filterOptions, state.queryParams] - ); - - const refetchCases = useCallback(() => { - fetchCases(state.filterOptions, state.queryParams); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [state.filterOptions, state.queryParams]); - - useEffect(() => { - fetchCases(state.filterOptions, state.queryParams); - return () => { - didCancelFetchCases.current = true; - didCancelUpdateCases.current = true; - abortCtrlFetchCases.current.abort(); - abortCtrlUpdateCases.current.abort(); - }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [state.queryParams, state.filterOptions]); - - return { - ...state, - dispatchUpdateCaseProperty, - refetchCases, - setFilters, - setQueryParams, - setSelectedCases, - }; -}; diff --git a/x-pack/plugins/cases/public/containers/use_get_tags.test.tsx b/x-pack/plugins/cases/public/containers/use_get_tags.test.tsx deleted file mode 100644 index 8042e560df35..000000000000 --- a/x-pack/plugins/cases/public/containers/use_get_tags.test.tsx +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { renderHook, act } from '@testing-library/react-hooks'; -import { useGetTags, UseGetTags } from './use_get_tags'; -import { tags } from './mock'; -import * as api from './api'; - -jest.mock('./api'); - -describe('useGetTags', () => { - const abortCtrl = new AbortController(); - beforeEach(() => { - jest.clearAllMocks(); - jest.restoreAllMocks(); - }); - - it('init', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, UseGetTags>(() => useGetTags()); - await waitForNextUpdate(); - expect(result.current).toEqual({ - tags: [], - isLoading: true, - isError: false, - fetchTags: result.current.fetchTags, - }); - }); - }); - - it('calls getTags api', async () => { - const spyOnGetTags = jest.spyOn(api, 'getTags'); - await act(async () => { - const { waitForNextUpdate } = renderHook<string, UseGetTags>(() => useGetTags()); - await waitForNextUpdate(); - await waitForNextUpdate(); - expect(spyOnGetTags).toBeCalledWith(abortCtrl.signal); - }); - }); - - it('fetch tags', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, UseGetTags>(() => useGetTags()); - await waitForNextUpdate(); - await waitForNextUpdate(); - expect(result.current).toEqual({ - tags, - isLoading: false, - isError: false, - fetchTags: result.current.fetchTags, - }); - }); - }); - - it('refetch tags', async () => { - const spyOnGetTags = jest.spyOn(api, 'getTags'); - await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, UseGetTags>(() => useGetTags()); - await waitForNextUpdate(); - await waitForNextUpdate(); - result.current.fetchTags(); - expect(spyOnGetTags).toHaveBeenCalledTimes(2); - }); - }); - - it('unhappy path', async () => { - const spyOnGetTags = jest.spyOn(api, 'getTags'); - spyOnGetTags.mockImplementation(() => { - throw new Error('Something went wrong'); - }); - - await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, UseGetTags>(() => useGetTags()); - await waitForNextUpdate(); - await waitForNextUpdate(); - - expect(result.current).toEqual({ - tags: [], - isLoading: false, - isError: true, - fetchTags: result.current.fetchTags, - }); - }); - }); -}); diff --git a/x-pack/plugins/cases/public/containers/use_get_tags.tsx b/x-pack/plugins/cases/public/containers/use_get_tags.tsx deleted file mode 100644 index 33b863fba5da..000000000000 --- a/x-pack/plugins/cases/public/containers/use_get_tags.tsx +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { useEffect, useReducer, useRef, useCallback } from 'react'; -import { errorToToaster, useStateToaster } from '../components/toasters'; -import { getTags } from './api'; -import * as i18n from './translations'; - -export interface TagsState { - tags: string[]; - isLoading: boolean; - isError: boolean; -} -type Action = - | { type: 'FETCH_INIT' } - | { type: 'FETCH_SUCCESS'; payload: string[] } - | { type: 'FETCH_FAILURE' }; - -export interface UseGetTags extends TagsState { - fetchTags: () => void; -} - -const dataFetchReducer = (state: TagsState, action: Action): TagsState => { - switch (action.type) { - case 'FETCH_INIT': - return { - ...state, - isLoading: true, - isError: false, - }; - case 'FETCH_SUCCESS': - return { - ...state, - isLoading: false, - isError: false, - tags: action.payload, - }; - case 'FETCH_FAILURE': - return { - ...state, - isLoading: false, - isError: true, - }; - default: - return state; - } -}; -const initialData: string[] = []; - -export const useGetTags = (): UseGetTags => { - const [state, dispatch] = useReducer(dataFetchReducer, { - isLoading: true, - isError: false, - tags: initialData, - }); - const [, dispatchToaster] = useStateToaster(); - const isCancelledRef = useRef(false); - const abortCtrlRef = useRef(new AbortController()); - - const callFetch = useCallback(async () => { - try { - isCancelledRef.current = false; - abortCtrlRef.current.abort(); - abortCtrlRef.current = new AbortController(); - dispatch({ type: 'FETCH_INIT' }); - - const response = await getTags(abortCtrlRef.current.signal); - - if (!isCancelledRef.current) { - dispatch({ type: 'FETCH_SUCCESS', payload: response }); - } - } catch (error) { - if (!isCancelledRef.current) { - if (error.name !== 'AbortError') { - errorToToaster({ - title: i18n.ERROR_TITLE, - error: error.body && error.body.message ? new Error(error.body.message) : error, - dispatchToaster, - }); - } - dispatch({ type: 'FETCH_FAILURE' }); - } - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - useEffect(() => { - callFetch(); - return () => { - isCancelledRef.current = true; - abortCtrlRef.current.abort(); - }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - return { ...state, fetchTags: callFetch }; -}; diff --git a/x-pack/plugins/cases/public/containers/use_post_case.test.tsx b/x-pack/plugins/cases/public/containers/use_post_case.test.tsx deleted file mode 100644 index 72ea368f1031..000000000000 --- a/x-pack/plugins/cases/public/containers/use_post_case.test.tsx +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { renderHook, act } from '@testing-library/react-hooks'; -import { usePostCase, UsePostCase } from './use_post_case'; -import * as api from './api'; -import { ConnectorTypes } from '../../common'; -import { basicCasePost } from './mock'; - -jest.mock('./api'); - -describe('usePostCase', () => { - const abortCtrl = new AbortController(); - const samplePost = { - description: 'description', - tags: ['tags'], - title: 'title', - connector: { - id: 'none', - name: 'none', - type: ConnectorTypes.none, - fields: null, - }, - settings: { - syncAlerts: true, - }, - }; - beforeEach(() => { - jest.clearAllMocks(); - jest.restoreAllMocks(); - }); - - it('init', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, UsePostCase>(() => usePostCase()); - await waitForNextUpdate(); - expect(result.current).toEqual({ - isLoading: false, - isError: false, - postCase: result.current.postCase, - }); - }); - }); - - it('calls postCase with correct arguments', async () => { - const spyOnPostCase = jest.spyOn(api, 'postCase'); - - await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, UsePostCase>(() => usePostCase()); - await waitForNextUpdate(); - - result.current.postCase(samplePost); - await waitForNextUpdate(); - expect(spyOnPostCase).toBeCalledWith(samplePost, abortCtrl.signal); - }); - }); - - it('calls postCase with correct result', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, UsePostCase>(() => usePostCase()); - await waitForNextUpdate(); - - const postData = await result.current.postCase(samplePost); - expect(postData).toEqual(basicCasePost); - }); - }); - - it('post case', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, UsePostCase>(() => usePostCase()); - await waitForNextUpdate(); - result.current.postCase(samplePost); - await waitForNextUpdate(); - expect(result.current).toEqual({ - isLoading: false, - isError: false, - postCase: result.current.postCase, - }); - }); - }); - - it('set isLoading to true when posting case', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, UsePostCase>(() => usePostCase()); - await waitForNextUpdate(); - result.current.postCase(samplePost); - - expect(result.current.isLoading).toBe(true); - }); - }); - - it('unhappy path', async () => { - const spyOnPostCase = jest.spyOn(api, 'postCase'); - spyOnPostCase.mockImplementation(() => { - throw new Error('Something went wrong'); - }); - - await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, UsePostCase>(() => usePostCase()); - await waitForNextUpdate(); - result.current.postCase(samplePost); - - expect(result.current).toEqual({ - isLoading: false, - isError: true, - postCase: result.current.postCase, - }); - }); - }); -}); diff --git a/x-pack/plugins/cases/public/containers/use_post_case.tsx b/x-pack/plugins/cases/public/containers/use_post_case.tsx deleted file mode 100644 index 503ac8bf0209..000000000000 --- a/x-pack/plugins/cases/public/containers/use_post_case.tsx +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { useReducer, useCallback, useRef, useEffect } from 'react'; -import { CasePostRequest } from '../../common'; -import { errorToToaster, useStateToaster } from '../components/toasters'; -import { postCase } from './api'; -import * as i18n from './translations'; -import { Case } from './types'; -interface NewCaseState { - isLoading: boolean; - isError: boolean; -} -type Action = { type: 'FETCH_INIT' } | { type: 'FETCH_SUCCESS' } | { type: 'FETCH_FAILURE' }; - -const dataFetchReducer = (state: NewCaseState, action: Action): NewCaseState => { - switch (action.type) { - case 'FETCH_INIT': - return { - ...state, - isLoading: true, - isError: false, - }; - case 'FETCH_SUCCESS': - return { - ...state, - isLoading: false, - isError: false, - }; - case 'FETCH_FAILURE': - return { - ...state, - isLoading: false, - isError: true, - }; - default: - return state; - } -}; -export interface UsePostCase extends NewCaseState { - postCase: (data: CasePostRequest) => Promise<Case | undefined>; -} -export const usePostCase = (): UsePostCase => { - const [state, dispatch] = useReducer(dataFetchReducer, { - isLoading: false, - isError: false, - }); - const [, dispatchToaster] = useStateToaster(); - const isCancelledRef = useRef(false); - const abortCtrlRef = useRef(new AbortController()); - - const postMyCase = useCallback(async (data: CasePostRequest) => { - try { - isCancelledRef.current = false; - abortCtrlRef.current.abort(); - abortCtrlRef.current = new AbortController(); - - dispatch({ type: 'FETCH_INIT' }); - const response = await postCase(data, abortCtrlRef.current.signal); - - if (!isCancelledRef.current) { - dispatch({ type: 'FETCH_SUCCESS' }); - } - return response; - } catch (error) { - if (!isCancelledRef.current) { - if (error.name !== 'AbortError') { - errorToToaster({ - title: i18n.ERROR_TITLE, - error: error.body && error.body.message ? new Error(error.body.message) : error, - dispatchToaster, - }); - } - dispatch({ type: 'FETCH_FAILURE' }); - } - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - useEffect(() => { - return () => { - isCancelledRef.current = true; - abortCtrlRef.current.abort(); - }; - }, []); - return { ...state, postCase: postMyCase }; -}; diff --git a/x-pack/plugins/cases/public/containers/use_post_push_to_service.test.tsx b/x-pack/plugins/cases/public/containers/use_post_push_to_service.test.tsx deleted file mode 100644 index 3d43180d60af..000000000000 --- a/x-pack/plugins/cases/public/containers/use_post_push_to_service.test.tsx +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { renderHook, act } from '@testing-library/react-hooks'; -import { usePostPushToService, UsePostPushToService } from './use_post_push_to_service'; -import { pushedCase } from './mock'; -import * as api from './api'; -import { CaseConnector, ConnectorTypes } from '../../common'; - -jest.mock('./api'); - -describe('usePostPushToService', () => { - const abortCtrl = new AbortController(); - const connector = { - id: '123', - name: 'connector name', - type: ConnectorTypes.jira, - fields: { issueType: 'Task', priority: 'Low', parent: null }, - } as CaseConnector; - const caseId = pushedCase.id; - - it('init', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, UsePostPushToService>(() => - usePostPushToService() - ); - await waitForNextUpdate(); - expect(result.current).toEqual({ - isLoading: false, - isError: false, - pushCaseToExternalService: result.current.pushCaseToExternalService, - }); - }); - }); - - it('calls pushCase with correct arguments', async () => { - const spyOnPushToService = jest.spyOn(api, 'pushCase'); - - await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, UsePostPushToService>(() => - usePostPushToService() - ); - await waitForNextUpdate(); - result.current.pushCaseToExternalService({ caseId, connector }); - await waitForNextUpdate(); - expect(spyOnPushToService).toBeCalledWith(caseId, connector.id, abortCtrl.signal); - }); - }); - - it('post push to service', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, UsePostPushToService>(() => - usePostPushToService() - ); - await waitForNextUpdate(); - result.current.pushCaseToExternalService({ caseId, connector }); - await waitForNextUpdate(); - expect(result.current).toEqual({ - isLoading: false, - isError: false, - pushCaseToExternalService: result.current.pushCaseToExternalService, - }); - }); - }); - - it('set isLoading to true when pushing case', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, UsePostPushToService>(() => - usePostPushToService() - ); - await waitForNextUpdate(); - result.current.pushCaseToExternalService({ caseId, connector }); - expect(result.current.isLoading).toBe(true); - }); - }); - - it('unhappy path', async () => { - const spyOnPushToService = jest.spyOn(api, 'pushCase'); - spyOnPushToService.mockImplementation(() => { - throw new Error('Something went wrong'); - }); - - await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, UsePostPushToService>(() => - usePostPushToService() - ); - await waitForNextUpdate(); - result.current.pushCaseToExternalService({ caseId, connector }); - - expect(result.current).toEqual({ - isLoading: false, - isError: true, - pushCaseToExternalService: result.current.pushCaseToExternalService, - }); - }); - }); -}); diff --git a/x-pack/plugins/cases/public/containers/use_post_push_to_service.tsx b/x-pack/plugins/cases/public/containers/use_post_push_to_service.tsx deleted file mode 100644 index 636edd33b5e9..000000000000 --- a/x-pack/plugins/cases/public/containers/use_post_push_to_service.tsx +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { useReducer, useCallback, useRef, useEffect } from 'react'; -import { CaseConnector } from '../../common'; -import { errorToToaster, useStateToaster, displaySuccessToast } from '../components/toasters'; - -import { pushCase } from './api'; -import * as i18n from './translations'; -import { Case } from './types'; - -interface PushToServiceState { - isLoading: boolean; - isError: boolean; -} -type Action = { type: 'FETCH_INIT' } | { type: 'FETCH_SUCCESS' } | { type: 'FETCH_FAILURE' }; - -const dataFetchReducer = (state: PushToServiceState, action: Action): PushToServiceState => { - switch (action.type) { - case 'FETCH_INIT': - return { - ...state, - isLoading: true, - isError: false, - }; - case 'FETCH_SUCCESS': - return { - ...state, - isLoading: false, - isError: false, - }; - case 'FETCH_FAILURE': - return { - ...state, - isLoading: false, - isError: true, - }; - default: - return state; - } -}; - -interface PushToServiceRequest { - caseId: string; - connector: CaseConnector; -} - -export interface UsePostPushToService extends PushToServiceState { - pushCaseToExternalService: ({ - caseId, - connector, - }: PushToServiceRequest) => Promise<Case | undefined>; -} - -export const usePostPushToService = (): UsePostPushToService => { - const [state, dispatch] = useReducer(dataFetchReducer, { - isLoading: false, - isError: false, - }); - const [, dispatchToaster] = useStateToaster(); - const cancel = useRef(false); - const abortCtrlRef = useRef(new AbortController()); - - const pushCaseToExternalService = useCallback( - async ({ caseId, connector }: PushToServiceRequest) => { - try { - abortCtrlRef.current.abort(); - cancel.current = false; - abortCtrlRef.current = new AbortController(); - dispatch({ type: 'FETCH_INIT' }); - - const response = await pushCase(caseId, connector.id, abortCtrlRef.current.signal); - - if (!cancel.current) { - dispatch({ type: 'FETCH_SUCCESS' }); - displaySuccessToast( - i18n.SUCCESS_SEND_TO_EXTERNAL_SERVICE(connector.name), - dispatchToaster - ); - } - - return response; - } catch (error) { - if (!cancel.current) { - if (error.name !== 'AbortError') { - errorToToaster({ - title: i18n.ERROR_TITLE, - error: error.body && error.body.message ? new Error(error.body.message) : error, - dispatchToaster, - }); - } - dispatch({ type: 'FETCH_FAILURE' }); - } - } - }, - // eslint-disable-next-line react-hooks/exhaustive-deps - [] - ); - - useEffect(() => { - return () => { - abortCtrlRef.current.abort(); - cancel.current = true; - }; - }, []); - - return { ...state, pushCaseToExternalService }; -}; diff --git a/x-pack/plugins/cases/public/containers/utils.test.ts b/x-pack/plugins/cases/public/containers/utils.test.ts deleted file mode 100644 index 6c1fb6029893..000000000000 --- a/x-pack/plugins/cases/public/containers/utils.test.ts +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - valueToUpdateIsSettings, - valueToUpdateIsStatus, - createUpdateSuccessToaster, -} from './utils'; - -import { Case } from './types'; - -const caseBeforeUpdate = { - comments: [ - { - type: 'alert', - }, - ], - settings: { - syncAlerts: true, - }, -} as Case; - -const caseAfterUpdate = { title: 'My case' } as Case; - -describe('utils', () => { - describe('valueToUpdateIsSettings', () => { - it('returns true if key is settings', () => { - expect(valueToUpdateIsSettings('settings', 'value')).toBe(true); - }); - - it('returns false if key is NOT settings', () => { - expect(valueToUpdateIsSettings('tags', 'value')).toBe(false); - }); - }); - - describe('valueToUpdateIsStatus', () => { - it('returns true if key is status', () => { - expect(valueToUpdateIsStatus('status', 'value')).toBe(true); - }); - - it('returns false if key is NOT status', () => { - expect(valueToUpdateIsStatus('tags', 'value')).toBe(false); - }); - }); - - describe('createUpdateSuccessToaster', () => { - it('creates the correct toast when sync alerts is turned on and case has alerts', () => { - // We remove the id as is randomly generated - const { id, ...toast } = createUpdateSuccessToaster( - caseBeforeUpdate, - caseAfterUpdate, - 'settings', - { - syncAlerts: true, - } - ); - - expect(toast).toEqual({ - color: 'success', - iconType: 'check', - title: 'Alerts in "My case" have been synced', - }); - }); - - it('creates the correct toast when sync alerts is turned on and case does NOT have alerts', () => { - // We remove the id as is randomly generated - const { id, ...toast } = createUpdateSuccessToaster( - { ...caseBeforeUpdate, comments: [] }, - caseAfterUpdate, - 'settings', - { - syncAlerts: true, - } - ); - - expect(toast).toEqual({ - color: 'success', - iconType: 'check', - title: 'Updated "My case"', - }); - }); - - it('creates the correct toast when sync alerts is turned off and case has alerts', () => { - // We remove the id as is randomly generated - const { id, ...toast } = createUpdateSuccessToaster( - caseBeforeUpdate, - caseAfterUpdate, - 'settings', - { - syncAlerts: false, - } - ); - - expect(toast).toEqual({ - color: 'success', - iconType: 'check', - title: 'Updated "My case"', - }); - }); - - it('creates the correct toast when the status change, case has alerts, and sync alerts is on', () => { - // We remove the id as is randomly generated - const { id, ...toast } = createUpdateSuccessToaster( - caseBeforeUpdate, - caseAfterUpdate, - 'status', - 'closed' - ); - - expect(toast).toEqual({ - color: 'success', - iconType: 'check', - title: 'Updated "My case"', - text: 'Alerts in this case have been also had their status updated', - }); - }); - - it('creates the correct toast when the status change, case has alerts, and sync alerts is off', () => { - // We remove the id as is randomly generated - const { id, ...toast } = createUpdateSuccessToaster( - { ...caseBeforeUpdate, settings: { syncAlerts: false } }, - caseAfterUpdate, - 'status', - 'closed' - ); - - expect(toast).toEqual({ - color: 'success', - iconType: 'check', - title: 'Updated "My case"', - }); - }); - - it('creates the correct toast when the status change, case does NOT have alerts, and sync alerts is on', () => { - // We remove the id as is randomly generated - const { id, ...toast } = createUpdateSuccessToaster( - { ...caseBeforeUpdate, comments: [] }, - caseAfterUpdate, - 'status', - 'closed' - ); - - expect(toast).toEqual({ - color: 'success', - iconType: 'check', - title: 'Updated "My case"', - }); - }); - - it('creates the correct toast if not a status or a setting', () => { - // We remove the id as is randomly generated - const { id, ...toast } = createUpdateSuccessToaster( - caseBeforeUpdate, - caseAfterUpdate, - 'title', - 'My new title' - ); - - expect(toast).toEqual({ - color: 'success', - iconType: 'check', - title: 'Updated "My case"', - }); - }); - }); -}); diff --git a/x-pack/plugins/cases/public/containers/utils.ts b/x-pack/plugins/cases/public/containers/utils.ts deleted file mode 100644 index a7eeaff1c263..000000000000 --- a/x-pack/plugins/cases/public/containers/utils.ts +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import uuid from 'uuid'; -import { set } from '@elastic/safer-lodash-set'; -import { camelCase, isArray, isObject } from 'lodash'; -import { fold } from 'fp-ts/lib/Either'; -import { identity } from 'fp-ts/lib/function'; -import { pipe } from 'fp-ts/lib/pipeable'; - -import { - CasesFindResponse, - CasesFindResponseRt, - CaseResponse, - CaseResponseRt, - CasesResponse, - CasesResponseRt, - CasesStatusResponseRt, - CasesStatusResponse, - throwErrors, - CasesConfigureResponse, - CaseConfigureResponseRt, - CaseUserActionsResponse, - CaseUserActionsResponseRt, - CommentType, - CasePatchRequest, -} from '../../common'; -import { AppToast, ToasterError } from '../components/toasters'; -import { AllCases, Case, UpdateByKey } from './types'; -import * as i18n from './translations'; - -export const getTypedPayload = <T>(a: unknown): T => a as T; - -export const parseString = (params: string) => { - try { - return JSON.parse(params); - } catch { - return null; - } -}; - -export const convertArrayToCamelCase = (arrayOfSnakes: unknown[]): unknown[] => - arrayOfSnakes.reduce((acc: unknown[], value) => { - if (isArray(value)) { - return [...acc, convertArrayToCamelCase(value)]; - } else if (isObject(value)) { - return [...acc, convertToCamelCase(value)]; - } else { - return [...acc, value]; - } - }, []); - -export const convertToCamelCase = <T, U extends {}>(snakeCase: T): U => - Object.entries(snakeCase).reduce((acc, [key, value]) => { - if (isArray(value)) { - set(acc, camelCase(key), convertArrayToCamelCase(value)); - } else if (isObject(value)) { - set(acc, camelCase(key), convertToCamelCase(value)); - } else { - set(acc, camelCase(key), value); - } - return acc; - }, {} as U); - -export const convertAllCasesToCamel = (snakeCases: CasesFindResponse): AllCases => ({ - cases: snakeCases.cases.map((snakeCase) => convertToCamelCase<CaseResponse, Case>(snakeCase)), - countOpenCases: snakeCases.count_open_cases, - countInProgressCases: snakeCases.count_in_progress_cases, - countClosedCases: snakeCases.count_closed_cases, - page: snakeCases.page, - perPage: snakeCases.per_page, - total: snakeCases.total, -}); - -export const decodeCasesStatusResponse = (respCase?: CasesStatusResponse) => - pipe( - CasesStatusResponseRt.decode(respCase), - fold(throwErrors(createToasterPlainError), identity) - ); - -export const createToasterPlainError = (message: string) => new ToasterError([message]); - -export const decodeCaseResponse = (respCase?: CaseResponse) => - pipe(CaseResponseRt.decode(respCase), fold(throwErrors(createToasterPlainError), identity)); - -export const decodeCasesResponse = (respCase?: CasesResponse) => - pipe(CasesResponseRt.decode(respCase), fold(throwErrors(createToasterPlainError), identity)); - -export const decodeCasesFindResponse = (respCases?: CasesFindResponse) => - pipe(CasesFindResponseRt.decode(respCases), fold(throwErrors(createToasterPlainError), identity)); - -export const decodeCaseConfigureResponse = (respCase?: CasesConfigureResponse) => - pipe( - CaseConfigureResponseRt.decode(respCase), - fold(throwErrors(createToasterPlainError), identity) - ); - -export const decodeCaseUserActionsResponse = (respUserActions?: CaseUserActionsResponse) => - pipe( - CaseUserActionsResponseRt.decode(respUserActions), - fold(throwErrors(createToasterPlainError), identity) - ); - -export const valueToUpdateIsSettings = ( - key: UpdateByKey['updateKey'], - value: UpdateByKey['updateValue'] -): value is CasePatchRequest['settings'] => key === 'settings'; - -export const valueToUpdateIsStatus = ( - key: UpdateByKey['updateKey'], - value: UpdateByKey['updateValue'] -): value is CasePatchRequest['status'] => key === 'status'; - -export const createUpdateSuccessToaster = ( - caseBeforeUpdate: Case, - caseAfterUpdate: Case, - key: UpdateByKey['updateKey'], - value: UpdateByKey['updateValue'] -): AppToast => { - const caseHasAlerts = caseBeforeUpdate.comments.some( - (comment) => comment.type === CommentType.alert - ); - - const toast: AppToast = { - id: uuid.v4(), - color: 'success', - iconType: 'check', - title: i18n.UPDATED_CASE(caseAfterUpdate.title), - }; - - if (valueToUpdateIsSettings(key, value) && value?.syncAlerts && caseHasAlerts) { - return { - ...toast, - title: i18n.SYNC_CASE(caseAfterUpdate.title), - }; - } - - if (valueToUpdateIsStatus(key, value) && caseHasAlerts && caseBeforeUpdate.settings.syncAlerts) { - return { - ...toast, - text: i18n.STATUS_CHANGED_TOASTER_TEXT, - }; - } - - return toast; -}; diff --git a/x-pack/plugins/cases/public/get_create_case.tsx b/x-pack/plugins/cases/public/get_create_case.tsx deleted file mode 100644 index ec13d9ae9e30..000000000000 --- a/x-pack/plugins/cases/public/get_create_case.tsx +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { lazy, Suspense } from 'react'; -import { EuiLoadingSpinner } from '@elastic/eui'; -import { CreateCaseProps } from './components/create'; - -export const getCreateCaseLazy = (props: CreateCaseProps) => { - const CreateCaseLazy = lazy(() => import('./components/create')); - return ( - <Suspense fallback={<EuiLoadingSpinner />}> - <CreateCaseLazy {...props} /> - </Suspense> - ); -}; diff --git a/x-pack/plugins/cases/public/index.tsx b/x-pack/plugins/cases/public/index.tsx deleted file mode 100644 index 1cf2d2e8d706..000000000000 --- a/x-pack/plugins/cases/public/index.tsx +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { PluginInitializerContext } from 'kibana/public'; -import React from 'react'; -import { CasesUiPlugin } from './plugin'; - -export const TestComponent = () => <div>{'Hello from cases plugin!'}</div>; - -export function plugin(initializerContext: PluginInitializerContext) { - return new CasesUiPlugin(initializerContext); -} - -export { CasesUiPlugin }; -export * from './plugin'; -export * from './types'; diff --git a/x-pack/plugins/cases/public/plugin.ts b/x-pack/plugins/cases/public/plugin.ts deleted file mode 100644 index c594e8677a08..000000000000 --- a/x-pack/plugins/cases/public/plugin.ts +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { CoreStart, Plugin, PluginInitializerContext } from 'src/core/public'; -import { TestComponent } from '.'; -import { CasesUiStart, SetupPlugins, StartPlugins } from './types'; -import { getCreateCaseLazy } from './get_create_case'; -import { KibanaServices } from './common/lib/kibana'; - -export class CasesUiPlugin implements Plugin<void, CasesUiStart, SetupPlugins, StartPlugins> { - private kibanaVersion: string; - - constructor(initializerContext: PluginInitializerContext) { - this.kibanaVersion = initializerContext.env.packageInfo.version; - } - public setup() {} - - public start(core: CoreStart, plugins: StartPlugins): CasesUiStart { - KibanaServices.init({ ...core, ...plugins, kibanaVersion: this.kibanaVersion }); - return { - casesComponent: TestComponent, - getCreateCase: (props) => { - return getCreateCaseLazy(props); - }, - }; - } - - public stop() {} -} diff --git a/x-pack/plugins/cases/public/types.ts b/x-pack/plugins/cases/public/types.ts deleted file mode 100644 index 07a0b2c72391..000000000000 --- a/x-pack/plugins/cases/public/types.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { CoreStart } from 'kibana/public'; -import { ReactElement } from 'react'; -import { - TriggersAndActionsUIPublicPluginSetup as TriggersActionsSetup, - TriggersAndActionsUIPublicPluginStart as TriggersActionsStart, -} from '../../triggers_actions_ui/public'; -import { CreateCaseProps } from './components/create'; - -export interface SetupPlugins { - triggersActionsUi: TriggersActionsSetup; -} - -export interface StartPlugins { - triggersActionsUi: TriggersActionsStart; -} - -export type StartServices = CoreStart & StartPlugins; - -export interface CasesUiStart { - casesComponent: () => JSX.Element; - getCreateCase: (props: CreateCaseProps) => ReactElement<CreateCaseProps>; -} diff --git a/x-pack/plugins/cases/server/client/alerts/update_status.test.ts b/x-pack/plugins/cases/server/client/alerts/update_status.test.ts index d6456cb3183e..5dfe6060da1d 100644 --- a/x-pack/plugins/cases/server/client/alerts/update_status.test.ts +++ b/x-pack/plugins/cases/server/client/alerts/update_status.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { CaseStatuses } from '../../../common'; +import { CaseStatuses } from '../../../common/api'; import { createMockSavedObjectsRepository } from '../../routes/api/__fixtures__'; import { createCasesClientWithMockSavedObjectsClient } from '../mocks'; diff --git a/x-pack/plugins/cases/server/client/cases/create.test.ts b/x-pack/plugins/cases/server/client/cases/create.test.ts index 9cbe2a448d3b..fe301dcca37a 100644 --- a/x-pack/plugins/cases/server/client/cases/create.test.ts +++ b/x-pack/plugins/cases/server/client/cases/create.test.ts @@ -5,7 +5,12 @@ * 2.0. */ -import { ConnectorTypes, CaseStatuses, CaseType, CasesClientPostRequest } from '../../../common'; +import { + ConnectorTypes, + CaseStatuses, + CaseType, + CasesClientPostRequest, +} from '../../../common/api'; import { isCaseError } from '../../common/error'; import { diff --git a/x-pack/plugins/cases/server/client/cases/create.ts b/x-pack/plugins/cases/server/client/cases/create.ts index 1dbb2dc496a9..59f968883634 100644 --- a/x-pack/plugins/cases/server/client/cases/create.ts +++ b/x-pack/plugins/cases/server/client/cases/create.ts @@ -22,7 +22,7 @@ import { CasePostRequest, CaseType, User, -} from '../../../common'; +} from '../../../common/api'; import { buildCaseUserActionItem } from '../../services/user_actions/helpers'; import { getConnectorFromConfiguration, diff --git a/x-pack/plugins/cases/server/client/cases/get.ts b/x-pack/plugins/cases/server/client/cases/get.ts index e230e665da86..fa556986ee8d 100644 --- a/x-pack/plugins/cases/server/client/cases/get.ts +++ b/x-pack/plugins/cases/server/client/cases/get.ts @@ -7,7 +7,7 @@ import { SavedObjectsClientContract, Logger } from 'kibana/server'; import { flattenCaseSavedObject } from '../../routes/api/utils'; -import { CaseResponseRt, CaseResponse } from '../../../common'; +import { CaseResponseRt, CaseResponse } from '../../../common/api'; import { CaseServiceSetup } from '../../services'; import { countAlertsForID } from '../../common'; import { createCaseError } from '../../common/error'; diff --git a/x-pack/plugins/cases/server/client/cases/mock.ts b/x-pack/plugins/cases/server/client/cases/mock.ts index 0e589b901c8d..490519187f49 100644 --- a/x-pack/plugins/cases/server/client/cases/mock.ts +++ b/x-pack/plugins/cases/server/client/cases/mock.ts @@ -12,7 +12,7 @@ import { CaseUserActionsResponse, AssociationType, CommentResponseAlertsType, -} from '../../../common'; +} from '../../../common/api'; import { BasicParams } from './types'; diff --git a/x-pack/plugins/cases/server/client/cases/push.ts b/x-pack/plugins/cases/server/client/cases/push.ts index eeaf91b13fa8..3217178768f8 100644 --- a/x-pack/plugins/cases/server/client/cases/push.ts +++ b/x-pack/plugins/cases/server/client/cases/push.ts @@ -29,7 +29,7 @@ import { User, ESCasesConfigureAttributes, CaseType, -} from '../../../common'; +} from '../../../common/api'; import { buildCaseUserActionItem } from '../../services/user_actions/helpers'; import { createIncident, getCommentContextFromAttributes } from './utils'; diff --git a/x-pack/plugins/cases/server/client/cases/types.ts b/x-pack/plugins/cases/server/client/cases/types.ts index fb400675136e..f1d56e7132bd 100644 --- a/x-pack/plugins/cases/server/client/cases/types.ts +++ b/x-pack/plugins/cases/server/client/cases/types.ts @@ -19,7 +19,7 @@ import { PushToServiceApiParamsSIR as ServiceNowSIRPushToServiceApiParams, ServiceNowITSMIncident, } from '../../../../actions/server/builtin_action_types/servicenow/types'; -import { CaseResponse, ConnectorMappingsAttributes } from '../../../common'; +import { CaseResponse, ConnectorMappingsAttributes } from '../../../common/api'; export type Incident = JiraIncident | ResilientIncident | ServiceNowITSMIncident; export type PushToServiceApiParams = diff --git a/x-pack/plugins/cases/server/client/cases/update.test.ts b/x-pack/plugins/cases/server/client/cases/update.test.ts index 18b4e8d9d7b6..79c3b2838c3b 100644 --- a/x-pack/plugins/cases/server/client/cases/update.test.ts +++ b/x-pack/plugins/cases/server/client/cases/update.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { ConnectorTypes, CasesPatchRequest, CaseStatuses } from '../../../common'; +import { ConnectorTypes, CasesPatchRequest, CaseStatuses } from '../../../common/api'; import { isCaseError } from '../../common/error'; import { createMockSavedObjectsRepository, diff --git a/x-pack/plugins/cases/server/client/cases/update.ts b/x-pack/plugins/cases/server/client/cases/update.ts index 6a59bf60a4ec..ff3c0a62407a 100644 --- a/x-pack/plugins/cases/server/client/cases/update.ts +++ b/x-pack/plugins/cases/server/client/cases/update.ts @@ -38,7 +38,7 @@ import { AssociationType, CommentAttributes, User, -} from '../../../common'; +} from '../../../common/api'; import { buildCaseUserActions } from '../../services/user_actions/helpers'; import { getCaseToUpdate, diff --git a/x-pack/plugins/cases/server/client/cases/utils.test.ts b/x-pack/plugins/cases/server/client/cases/utils.test.ts index c24812048376..859114a5e8fb 100644 --- a/x-pack/plugins/cases/server/client/cases/utils.test.ts +++ b/x-pack/plugins/cases/server/client/cases/utils.test.ts @@ -539,7 +539,7 @@ describe('utils', () => { commentId: 'comment-user-1', }, { - comment: 'Elastic Alerts attached to the case: 3', + comment: 'Elastic Security Alerts attached to the case: 3', commentId: 'mock-id-1-total-alerts', }, ]); @@ -569,7 +569,7 @@ describe('utils', () => { commentId: 'comment-user-1', }, { - comment: 'Elastic Alerts attached to the case: 4', + comment: 'Elastic Security Alerts attached to the case: 4', commentId: 'mock-id-1-total-alerts', }, ]); diff --git a/x-pack/plugins/cases/server/client/cases/utils.ts b/x-pack/plugins/cases/server/client/cases/utils.ts index 7749bce8042e..7e77bf4ac84c 100644 --- a/x-pack/plugins/cases/server/client/cases/utils.ts +++ b/x-pack/plugins/cases/server/client/cases/utils.ts @@ -20,7 +20,7 @@ import { CommentAttributes, CommentRequestUserType, CommentRequestAlertType, -} from '../../../common'; +} from '../../../common/api'; import { ActionsClient } from '../../../../actions/server'; import { externalServiceFormatters, FormatterConnectorTypes } from '../../connectors'; import { CasesClientGetAlertsResponse } from '../../client/alerts/types'; @@ -184,7 +184,7 @@ export const createIncident = async ({ if (totalAlerts > 0) { comments.push({ - comment: `Elastic Alerts attached to the case: ${totalAlerts}`, + comment: `Elastic Security Alerts attached to the case: ${totalAlerts}`, commentId: `${theCase.id}-total-alerts`, }); } diff --git a/x-pack/plugins/cases/server/client/client.ts b/x-pack/plugins/cases/server/client/client.ts index 3bd25b6b61bc..8f9058654d6f 100644 --- a/x-pack/plugins/cases/server/client/client.ts +++ b/x-pack/plugins/cases/server/client/client.ts @@ -31,7 +31,7 @@ import { CaseUserActionServiceSetup, AlertServiceContract, } from '../services'; -import { CasesPatchRequest, CasePostRequest, User } from '../../common'; +import { CasesPatchRequest, CasePostRequest, User } from '../../common/api'; import { get } from './cases/get'; import { get as getUserActions } from './user_actions/get'; import { get as getAlerts } from './alerts/get'; diff --git a/x-pack/plugins/cases/server/client/comments/add.test.ts b/x-pack/plugins/cases/server/client/comments/add.test.ts index bd04e0ea6ef1..23b7bc37dc81 100644 --- a/x-pack/plugins/cases/server/client/comments/add.test.ts +++ b/x-pack/plugins/cases/server/client/comments/add.test.ts @@ -6,7 +6,7 @@ */ import { omit } from 'lodash/fp'; -import { CommentType } from '../../../common'; +import { CommentType } from '../../../common/api'; import { isCaseError } from '../../common/error'; import { createMockSavedObjectsRepository, diff --git a/x-pack/plugins/cases/server/client/comments/add.ts b/x-pack/plugins/cases/server/client/comments/add.ts index 98b914fb7486..45746613dc1d 100644 --- a/x-pack/plugins/cases/server/client/comments/add.ts +++ b/x-pack/plugins/cases/server/client/comments/add.ts @@ -25,7 +25,7 @@ import { User, CommentRequestAlertType, AlertCommentRequestRt, -} from '../../../common'; +} from '../../../common/api'; import { buildCaseUserActionItem, buildCommentUserActionItem, @@ -36,7 +36,7 @@ import { CommentableCase, createAlertUpdateRequest } from '../../common'; import { CasesClientHandler } from '..'; import { createCaseError } from '../../common/error'; import { CASE_COMMENT_SAVED_OBJECT } from '../../saved_object_types'; -import { MAX_GENERATED_ALERTS_PER_SUB_CASE } from '../../../common'; +import { MAX_GENERATED_ALERTS_PER_SUB_CASE } from '../../../common/constants'; async function getSubCase({ caseService, diff --git a/x-pack/plugins/cases/server/client/configure/get_fields.test.ts b/x-pack/plugins/cases/server/client/configure/get_fields.test.ts index c474361293da..2e2973516d0f 100644 --- a/x-pack/plugins/cases/server/client/configure/get_fields.test.ts +++ b/x-pack/plugins/cases/server/client/configure/get_fields.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { ConnectorTypes } from '../../../common'; +import { ConnectorTypes } from '../../../common/api'; import { createMockSavedObjectsRepository, mockCaseMappings } from '../../routes/api/__fixtures__'; import { createCasesClientWithMockSavedObjectsClient } from '../mocks'; diff --git a/x-pack/plugins/cases/server/client/configure/get_fields.ts b/x-pack/plugins/cases/server/client/configure/get_fields.ts index 8d899f0df1a7..deabae33810b 100644 --- a/x-pack/plugins/cases/server/client/configure/get_fields.ts +++ b/x-pack/plugins/cases/server/client/configure/get_fields.ts @@ -7,7 +7,7 @@ import Boom from '@hapi/boom'; -import { GetFieldsResponse } from '../../../common'; +import { GetFieldsResponse } from '../../../common/api'; import { ConfigureFields } from '../types'; import { createDefaultMapping, formatFields } from './utils'; diff --git a/x-pack/plugins/cases/server/client/configure/get_mappings.test.ts b/x-pack/plugins/cases/server/client/configure/get_mappings.test.ts index 7d9593899bb2..0ec2fc8b4621 100644 --- a/x-pack/plugins/cases/server/client/configure/get_mappings.test.ts +++ b/x-pack/plugins/cases/server/client/configure/get_mappings.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { ConnectorTypes } from '../../../common'; +import { ConnectorTypes } from '../../../common/api'; import { createMockSavedObjectsRepository, mockCaseMappings } from '../../routes/api/__fixtures__'; import { createCasesClientWithMockSavedObjectsClient } from '../mocks'; diff --git a/x-pack/plugins/cases/server/client/configure/get_mappings.ts b/x-pack/plugins/cases/server/client/configure/get_mappings.ts index 1f767ea68284..558c961f89e5 100644 --- a/x-pack/plugins/cases/server/client/configure/get_mappings.ts +++ b/x-pack/plugins/cases/server/client/configure/get_mappings.ts @@ -7,7 +7,7 @@ import { SavedObjectsClientContract, Logger } from 'src/core/server'; import { ActionsClient } from '../../../../actions/server'; -import { ConnectorMappingsAttributes, ConnectorTypes } from '../../../common'; +import { ConnectorMappingsAttributes, ConnectorTypes } from '../../../common/api'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { ACTION_SAVED_OBJECT_TYPE } from '../../../../actions/server/saved_objects'; import { ConnectorMappingsServiceSetup } from '../../services'; diff --git a/x-pack/plugins/cases/server/client/configure/mock.ts b/x-pack/plugins/cases/server/client/configure/mock.ts index ad982a5cc124..ee214de9b51d 100644 --- a/x-pack/plugins/cases/server/client/configure/mock.ts +++ b/x-pack/plugins/cases/server/client/configure/mock.ts @@ -5,7 +5,11 @@ * 2.0. */ -import { ConnectorField, ConnectorMappingsAttributes, ConnectorTypes } from '../../../common'; +import { + ConnectorField, + ConnectorMappingsAttributes, + ConnectorTypes, +} from '../../../common/api/connectors'; import { JiraGetFieldsResponse, ResilientGetFieldsResponse, diff --git a/x-pack/plugins/cases/server/client/configure/utils.test.ts b/x-pack/plugins/cases/server/client/configure/utils.test.ts index bf571388994c..403854693e36 100644 --- a/x-pack/plugins/cases/server/client/configure/utils.test.ts +++ b/x-pack/plugins/cases/server/client/configure/utils.test.ts @@ -11,7 +11,7 @@ export { ServiceNowGetFieldsResponse, } from '../../../../actions/server/types'; import { createDefaultMapping, formatFields } from './utils'; -import { ConnectorTypes } from '../../../common'; +import { ConnectorTypes } from '../../../common/api/connectors'; import { mappings, formatFieldsTestData } from './mock'; describe('client/configure/utils', () => { diff --git a/x-pack/plugins/cases/server/client/configure/utils.ts b/x-pack/plugins/cases/server/client/configure/utils.ts index b9ef813735e2..80e6c7a3b886 100644 --- a/x-pack/plugins/cases/server/client/configure/utils.ts +++ b/x-pack/plugins/cases/server/client/configure/utils.ts @@ -5,7 +5,11 @@ * 2.0. */ -import { ConnectorField, ConnectorMappingsAttributes, ConnectorTypes } from '../../../common'; +import { + ConnectorField, + ConnectorMappingsAttributes, + ConnectorTypes, +} from '../../../common/api/connectors'; import { JiraGetFieldsResponse, ResilientGetFieldsResponse, diff --git a/x-pack/plugins/cases/server/client/types.ts b/x-pack/plugins/cases/server/client/types.ts index 3311b7ac6f92..c62b3913da76 100644 --- a/x-pack/plugins/cases/server/client/types.ts +++ b/x-pack/plugins/cases/server/client/types.ts @@ -18,7 +18,7 @@ import { GetFieldsResponse, CaseUserActionsResponse, User, -} from '../../common'; +} from '../../common/api'; import { AlertInfo } from '../common'; import { CaseConfigureServiceSetup, diff --git a/x-pack/plugins/cases/server/client/user_actions/get.ts b/x-pack/plugins/cases/server/client/user_actions/get.ts index 79b8ef25ab0f..f6371b8e8b1e 100644 --- a/x-pack/plugins/cases/server/client/user_actions/get.ts +++ b/x-pack/plugins/cases/server/client/user_actions/get.ts @@ -11,7 +11,7 @@ import { CASE_COMMENT_SAVED_OBJECT, SUB_CASE_SAVED_OBJECT, } from '../../saved_object_types'; -import { CaseUserActionsResponseRt, CaseUserActionsResponse } from '../../../common'; +import { CaseUserActionsResponseRt, CaseUserActionsResponse } from '../../../common/api'; import { CaseUserActionServiceSetup } from '../../services'; interface GetParams { diff --git a/x-pack/plugins/cases/server/common/models/commentable_case.ts b/x-pack/plugins/cases/server/common/models/commentable_case.ts index 3daccf87bdc1..1ff5b7beadca 100644 --- a/x-pack/plugins/cases/server/common/models/commentable_case.ts +++ b/x-pack/plugins/cases/server/common/models/commentable_case.ts @@ -27,7 +27,7 @@ import { ESCaseAttributes, SubCaseAttributes, User, -} from '../../../common'; +} from '../../../common/api'; import { transformESConnectorToCaseConnector } from '../../routes/api/cases/helpers'; import { flattenCommentSavedObjects, diff --git a/x-pack/plugins/cases/server/common/utils.test.ts b/x-pack/plugins/cases/server/common/utils.test.ts index df16fe4f0a67..5e6a86358de2 100644 --- a/x-pack/plugins/cases/server/common/utils.test.ts +++ b/x-pack/plugins/cases/server/common/utils.test.ts @@ -6,7 +6,7 @@ */ import { SavedObjectsFindResponse } from 'kibana/server'; -import { AssociationType, CommentAttributes, CommentRequest, CommentType } from '../../common'; +import { AssociationType, CommentAttributes, CommentRequest, CommentType } from '../../common/api'; import { transformNewComment } from '../routes/api/utils'; import { combineFilters, countAlerts, countAlertsForID, groupTotalAlertsByID } from './utils'; diff --git a/x-pack/plugins/cases/server/common/utils.ts b/x-pack/plugins/cases/server/common/utils.ts index d3bc3850e421..dce26f3d5998 100644 --- a/x-pack/plugins/cases/server/common/utils.ts +++ b/x-pack/plugins/cases/server/common/utils.ts @@ -6,7 +6,13 @@ */ import { SavedObjectsFindResult, SavedObjectsFindResponse } from 'kibana/server'; -import { CaseStatuses, CommentAttributes, CommentRequest, CommentType, User } from '../../common'; +import { + CaseStatuses, + CommentAttributes, + CommentRequest, + CommentType, + User, +} from '../../common/api'; import { UpdateAlertRequest } from '../client/types'; import { getAlertInfoFromComments } from '../routes/api/utils'; diff --git a/x-pack/plugins/cases/server/connectors/case/index.test.ts b/x-pack/plugins/cases/server/connectors/case/index.test.ts index b8c80a101f4c..fa2b10a0ccbd 100644 --- a/x-pack/plugins/cases/server/connectors/case/index.test.ts +++ b/x-pack/plugins/cases/server/connectors/case/index.test.ts @@ -18,7 +18,7 @@ import { AssociationType, CaseResponse, CasesResponse, -} from '../../../common'; +} from '../../../common/api'; import { connectorMappingsServiceMock, createCaseServiceMock, diff --git a/x-pack/plugins/cases/server/connectors/case/index.ts b/x-pack/plugins/cases/server/connectors/case/index.ts index d223c70221e3..da993faf0ef5 100644 --- a/x-pack/plugins/cases/server/connectors/case/index.ts +++ b/x-pack/plugins/cases/server/connectors/case/index.ts @@ -8,7 +8,12 @@ import { curry } from 'lodash'; import { Logger } from 'src/core/server'; import { ActionTypeExecutorResult } from '../../../../actions/common'; -import { CasePatchRequest, CasePostRequest, CommentRequest, CommentType } from '../../../common'; +import { + CasePatchRequest, + CasePostRequest, + CommentRequest, + CommentType, +} from '../../../common/api'; import { createExternalCasesClient } from '../../client'; import { CaseExecutorParamsSchema, CaseConfigurationSchema, CommentSchemaType } from './schema'; import { diff --git a/x-pack/plugins/cases/server/connectors/case/schema.ts b/x-pack/plugins/cases/server/connectors/case/schema.ts index 803b01cbbdc5..1637cec7520b 100644 --- a/x-pack/plugins/cases/server/connectors/case/schema.ts +++ b/x-pack/plugins/cases/server/connectors/case/schema.ts @@ -6,7 +6,7 @@ */ import { schema } from '@kbn/config-schema'; -import { CommentType } from '../../../common'; +import { CommentType } from '../../../common/api'; import { validateConnector } from './validators'; // Reserved for future implementation diff --git a/x-pack/plugins/cases/server/connectors/case/types.ts b/x-pack/plugins/cases/server/connectors/case/types.ts index a71007f0b494..6a7dfd9c2e68 100644 --- a/x-pack/plugins/cases/server/connectors/case/types.ts +++ b/x-pack/plugins/cases/server/connectors/case/types.ts @@ -16,7 +16,7 @@ import { ConnectorSchema, CommentSchema, } from './schema'; -import { CaseResponse, CasesResponse } from '../../../common'; +import { CaseResponse, CasesResponse } from '../../../common/api'; export type CaseConfiguration = TypeOf<typeof CaseConfigurationSchema>; export type Connector = TypeOf<typeof ConnectorSchema>; diff --git a/x-pack/plugins/cases/server/connectors/index.ts b/x-pack/plugins/cases/server/connectors/index.ts index ecf04e4f7b0f..a6b6e193361b 100644 --- a/x-pack/plugins/cases/server/connectors/index.ts +++ b/x-pack/plugins/cases/server/connectors/index.ts @@ -17,7 +17,7 @@ import { serviceNowITSMExternalServiceFormatter } from './servicenow/itsm_format import { serviceNowSIRExternalServiceFormatter } from './servicenow/sir_formatter'; import { jiraExternalServiceFormatter } from './jira/external_service_formatter'; import { resilientExternalServiceFormatter } from './resilient/external_service_formatter'; -import { CommentRequest, CommentType } from '../../common'; +import { CommentRequest, CommentType } from '../../common/api'; export * from './types'; export { transformConnectorComment } from './case'; diff --git a/x-pack/plugins/cases/server/connectors/jira/external_service_formatter.test.ts b/x-pack/plugins/cases/server/connectors/jira/external_service_formatter.test.ts index f5d76aeddf31..0bfaf7cdbd9e 100644 --- a/x-pack/plugins/cases/server/connectors/jira/external_service_formatter.test.ts +++ b/x-pack/plugins/cases/server/connectors/jira/external_service_formatter.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { CaseResponse } from '../../../common'; +import { CaseResponse } from '../../../common/api'; import { jiraExternalServiceFormatter } from './external_service_formatter'; describe('Jira formatter', () => { diff --git a/x-pack/plugins/cases/server/connectors/jira/external_service_formatter.ts b/x-pack/plugins/cases/server/connectors/jira/external_service_formatter.ts index 15ee2fd468dd..74376d295fea 100644 --- a/x-pack/plugins/cases/server/connectors/jira/external_service_formatter.ts +++ b/x-pack/plugins/cases/server/connectors/jira/external_service_formatter.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { JiraFieldsType, ConnectorJiraTypeFields } from '../../../common'; +import { JiraFieldsType, ConnectorJiraTypeFields } from '../../../common/api'; import { ExternalServiceFormatter } from '../types'; interface ExternalServiceParams extends JiraFieldsType { diff --git a/x-pack/plugins/cases/server/connectors/resilient/external_service_formatter.test.ts b/x-pack/plugins/cases/server/connectors/resilient/external_service_formatter.test.ts index b7096179b0fa..01280e9692b5 100644 --- a/x-pack/plugins/cases/server/connectors/resilient/external_service_formatter.test.ts +++ b/x-pack/plugins/cases/server/connectors/resilient/external_service_formatter.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { CaseResponse } from '../../../common'; +import { CaseResponse } from '../../../common/api'; import { resilientExternalServiceFormatter } from './external_service_formatter'; describe('IBM Resilient formatter', () => { diff --git a/x-pack/plugins/cases/server/connectors/resilient/external_service_formatter.ts b/x-pack/plugins/cases/server/connectors/resilient/external_service_formatter.ts index 6dea452565d7..76554dce3279 100644 --- a/x-pack/plugins/cases/server/connectors/resilient/external_service_formatter.ts +++ b/x-pack/plugins/cases/server/connectors/resilient/external_service_formatter.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { ResilientFieldsType, ConnectorResillientTypeFields } from '../../../common'; +import { ResilientFieldsType, ConnectorResillientTypeFields } from '../../../common/api'; import { ExternalServiceFormatter } from '../types'; const format: ExternalServiceFormatter<ResilientFieldsType>['format'] = (theCase) => { diff --git a/x-pack/plugins/cases/server/connectors/servicenow/itsm_formatter.ts b/x-pack/plugins/cases/server/connectors/servicenow/itsm_formatter.ts index a4fa8a198fea..b49eed6a4ad2 100644 --- a/x-pack/plugins/cases/server/connectors/servicenow/itsm_formatter.ts +++ b/x-pack/plugins/cases/server/connectors/servicenow/itsm_formatter.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { ServiceNowITSMFieldsType, ConnectorServiceNowITSMTypeFields } from '../../../common'; +import { ServiceNowITSMFieldsType, ConnectorServiceNowITSMTypeFields } from '../../../common/api'; import { ExternalServiceFormatter } from '../types'; const format: ExternalServiceFormatter<ServiceNowITSMFieldsType>['format'] = (theCase) => { diff --git a/x-pack/plugins/cases/server/connectors/servicenow/itsm_formmater.test.ts b/x-pack/plugins/cases/server/connectors/servicenow/itsm_formmater.test.ts index 78242e4c3848..ea3a4e41e17b 100644 --- a/x-pack/plugins/cases/server/connectors/servicenow/itsm_formmater.test.ts +++ b/x-pack/plugins/cases/server/connectors/servicenow/itsm_formmater.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { CaseResponse } from '../../../common'; +import { CaseResponse } from '../../../common/api'; import { serviceNowITSMExternalServiceFormatter } from './itsm_formatter'; describe('ITSM formatter', () => { diff --git a/x-pack/plugins/cases/server/connectors/servicenow/sir_formatter.test.ts b/x-pack/plugins/cases/server/connectors/servicenow/sir_formatter.test.ts index 1f7716424cfa..4faca62c6e70 100644 --- a/x-pack/plugins/cases/server/connectors/servicenow/sir_formatter.test.ts +++ b/x-pack/plugins/cases/server/connectors/servicenow/sir_formatter.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { CaseResponse } from '../../../common'; +import { CaseResponse } from '../../../common/api'; import { serviceNowSIRExternalServiceFormatter } from './sir_formatter'; describe('ITSM formatter', () => { diff --git a/x-pack/plugins/cases/server/connectors/servicenow/sir_formatter.ts b/x-pack/plugins/cases/server/connectors/servicenow/sir_formatter.ts index 1c528cd2b47b..d2458e6c7ae5 100644 --- a/x-pack/plugins/cases/server/connectors/servicenow/sir_formatter.ts +++ b/x-pack/plugins/cases/server/connectors/servicenow/sir_formatter.ts @@ -5,7 +5,7 @@ * 2.0. */ import { get } from 'lodash/fp'; -import { ConnectorServiceNowSIRTypeFields } from '../../../common'; +import { ConnectorServiceNowSIRTypeFields } from '../../../common/api'; import { ExternalServiceFormatter } from '../types'; interface ExternalServiceParams { dest_ip: string | null; diff --git a/x-pack/plugins/cases/server/connectors/types.ts b/x-pack/plugins/cases/server/connectors/types.ts index fae1ec2976bc..f6c284b74667 100644 --- a/x-pack/plugins/cases/server/connectors/types.ts +++ b/x-pack/plugins/cases/server/connectors/types.ts @@ -13,7 +13,7 @@ import { ActionType, // eslint-disable-next-line @kbn/eslint/no-restricted-paths } from '../../../actions/server/types'; -import { CaseResponse, ConnectorTypes } from '../../common'; +import { CaseResponse, ConnectorTypes } from '../../common/api'; import { CasesClientGetAlertsResponse } from '../client/alerts/types'; import { CaseServiceSetup, diff --git a/x-pack/plugins/cases/server/plugin.ts b/x-pack/plugins/cases/server/plugin.ts index 82e2e0b10e77..0c661cc18c21 100644 --- a/x-pack/plugins/cases/server/plugin.ts +++ b/x-pack/plugins/cases/server/plugin.ts @@ -10,7 +10,7 @@ import { CoreSetup, CoreStart } from 'src/core/server'; import { SecurityPluginSetup } from '../../security/server'; import { PluginSetupContract as ActionsPluginSetup } from '../../actions/server'; -import { APP_ID } from '../common'; +import { APP_ID } from '../common/constants'; import { ConfigType } from './config'; import { initCaseApi } from './routes/api'; diff --git a/x-pack/plugins/cases/server/routes/api/__fixtures__/mock_saved_objects.ts b/x-pack/plugins/cases/server/routes/api/__fixtures__/mock_saved_objects.ts index c9d7ac412514..f2318c45e6ed 100644 --- a/x-pack/plugins/cases/server/routes/api/__fixtures__/mock_saved_objects.ts +++ b/x-pack/plugins/cases/server/routes/api/__fixtures__/mock_saved_objects.ts @@ -17,7 +17,7 @@ import { ConnectorTypes, ESCaseAttributes, ESCasesConfigureAttributes, -} from '../../../../common'; +} from '../../../../common/api'; import { CASE_CONNECTOR_MAPPINGS_SAVED_OBJECT, CASE_USER_ACTION_SAVED_OBJECT, diff --git a/x-pack/plugins/cases/server/routes/api/__mocks__/request_responses.ts b/x-pack/plugins/cases/server/routes/api/__mocks__/request_responses.ts index 9df94cd0923c..ae14b44e7dff 100644 --- a/x-pack/plugins/cases/server/routes/api/__mocks__/request_responses.ts +++ b/x-pack/plugins/cases/server/routes/api/__mocks__/request_responses.ts @@ -10,7 +10,7 @@ import { CasePostRequest, CasesConfigureRequest, ConnectorTypes, -} from '../../../../common'; +} from '../../../../common/api'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { FindActionResult } from '../../../../../actions/server/types'; diff --git a/x-pack/plugins/cases/server/routes/api/cases/comments/delete_all_comments.ts b/x-pack/plugins/cases/server/routes/api/cases/comments/delete_all_comments.ts index 77db06680fd5..fd250b74fff1 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/comments/delete_all_comments.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/comments/delete_all_comments.ts @@ -10,7 +10,8 @@ import { schema } from '@kbn/config-schema'; import { buildCommentUserActionItem } from '../../../../services/user_actions/helpers'; import { RouteDeps } from '../../types'; import { wrapError } from '../../utils'; -import { AssociationType, CASE_COMMENTS_URL } from '../../../../../common'; +import { CASE_COMMENTS_URL } from '../../../../../common/constants'; +import { AssociationType } from '../../../../../common/api'; export function initDeleteAllCommentsApi({ caseService, diff --git a/x-pack/plugins/cases/server/routes/api/cases/comments/delete_comment.test.ts b/x-pack/plugins/cases/server/routes/api/cases/comments/delete_comment.test.ts index d0968c323245..dcbcd7b9e246 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/comments/delete_comment.test.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/comments/delete_comment.test.ts @@ -16,7 +16,7 @@ import { mockCaseComments, } from '../../__fixtures__'; import { initDeleteCommentApi } from './delete_comment'; -import { CASE_COMMENT_DETAILS_URL } from '../../../../../common'; +import { CASE_COMMENT_DETAILS_URL } from '../../../../../common/constants'; describe('DELETE comment', () => { let routeHandler: RequestHandler<any, any, any>; diff --git a/x-pack/plugins/cases/server/routes/api/cases/comments/delete_comment.ts b/x-pack/plugins/cases/server/routes/api/cases/comments/delete_comment.ts index 3ba93142bdcc..f1c5fdc2b7cc 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/comments/delete_comment.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/comments/delete_comment.ts @@ -12,7 +12,7 @@ import { CASE_SAVED_OBJECT, SUB_CASE_SAVED_OBJECT } from '../../../../saved_obje import { buildCommentUserActionItem } from '../../../../services/user_actions/helpers'; import { RouteDeps } from '../../types'; import { wrapError } from '../../utils'; -import { CASE_COMMENT_DETAILS_URL } from '../../../../../common'; +import { CASE_COMMENT_DETAILS_URL } from '../../../../../common/constants'; export function initDeleteCommentApi({ caseService, diff --git a/x-pack/plugins/cases/server/routes/api/cases/comments/find_comments.ts b/x-pack/plugins/cases/server/routes/api/cases/comments/find_comments.ts index 75d0f9f59657..57ddd84e8742 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/comments/find_comments.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/comments/find_comments.ts @@ -19,10 +19,10 @@ import { CommentsResponseRt, SavedObjectFindOptionsRt, throwErrors, -} from '../../../../../common'; +} from '../../../../../common/api'; import { RouteDeps } from '../../types'; import { escapeHatch, transformComments, wrapError } from '../../utils'; -import { CASE_COMMENTS_URL } from '../../../../../common'; +import { CASE_COMMENTS_URL } from '../../../../../common/constants'; import { defaultPage, defaultPerPage } from '../..'; const FindQueryParamsRt = rt.partial({ diff --git a/x-pack/plugins/cases/server/routes/api/cases/comments/get_all_comment.ts b/x-pack/plugins/cases/server/routes/api/cases/comments/get_all_comment.ts index a400f944dddf..770efe010974 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/comments/get_all_comment.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/comments/get_all_comment.ts @@ -8,10 +8,10 @@ import { schema } from '@kbn/config-schema'; import { SavedObjectsFindResponse } from 'kibana/server'; -import { AllCommentsResponseRt, CommentAttributes } from '../../../../../common'; +import { AllCommentsResponseRt, CommentAttributes } from '../../../../../common/api'; import { RouteDeps } from '../../types'; import { flattenCommentSavedObjects, wrapError } from '../../utils'; -import { CASE_COMMENTS_URL } from '../../../../../common'; +import { CASE_COMMENTS_URL } from '../../../../../common/constants'; import { defaultSortField } from '../../../../common'; export function initGetAllCommentsApi({ caseService, router, logger }: RouteDeps) { diff --git a/x-pack/plugins/cases/server/routes/api/cases/comments/get_comment.test.ts b/x-pack/plugins/cases/server/routes/api/cases/comments/get_comment.test.ts index 46accdc58d46..8ee43eaba8a8 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/comments/get_comment.test.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/comments/get_comment.test.ts @@ -17,7 +17,7 @@ import { } from '../../__fixtures__'; import { flattenCommentSavedObject } from '../../utils'; import { initGetCommentApi } from './get_comment'; -import { CASE_COMMENT_DETAILS_URL } from '../../../../../common'; +import { CASE_COMMENT_DETAILS_URL } from '../../../../../common/constants'; describe('GET comment', () => { let routeHandler: RequestHandler<any, any, any>; diff --git a/x-pack/plugins/cases/server/routes/api/cases/comments/get_comment.ts b/x-pack/plugins/cases/server/routes/api/cases/comments/get_comment.ts index f86f73330604..9dedfccd3a25 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/comments/get_comment.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/comments/get_comment.ts @@ -7,10 +7,10 @@ import { schema } from '@kbn/config-schema'; -import { CommentResponseRt } from '../../../../../common'; +import { CommentResponseRt } from '../../../../../common/api'; import { RouteDeps } from '../../types'; import { flattenCommentSavedObject, wrapError } from '../../utils'; -import { CASE_COMMENT_DETAILS_URL } from '../../../../../common'; +import { CASE_COMMENT_DETAILS_URL } from '../../../../../common/constants'; export function initGetCommentApi({ caseService, router, logger }: RouteDeps) { router.get( diff --git a/x-pack/plugins/cases/server/routes/api/cases/comments/patch_comment.test.ts b/x-pack/plugins/cases/server/routes/api/cases/comments/patch_comment.test.ts index 32a0133d455c..9cc0575f9bb9 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/comments/patch_comment.test.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/comments/patch_comment.test.ts @@ -17,8 +17,8 @@ import { mockCases, } from '../../__fixtures__'; import { initPatchCommentApi } from './patch_comment'; -import { CASE_COMMENTS_URL } from '../../../../../common'; -import { CommentType } from '../../../../../common'; +import { CASE_COMMENTS_URL } from '../../../../../common/constants'; +import { CommentType } from '../../../../../common/api'; describe('PATCH comment', () => { let routeHandler: RequestHandler<any, any, any>; diff --git a/x-pack/plugins/cases/server/routes/api/cases/comments/patch_comment.ts b/x-pack/plugins/cases/server/routes/api/cases/comments/patch_comment.ts index b47236f4693c..f5db2dc004a1 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/comments/patch_comment.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/comments/patch_comment.ts @@ -14,12 +14,12 @@ import Boom from '@hapi/boom'; import { SavedObjectsClientContract, Logger } from 'kibana/server'; import { CommentableCase } from '../../../../common'; -import { CommentPatchRequestRt, throwErrors, User } from '../../../../../common'; +import { CommentPatchRequestRt, throwErrors, User } from '../../../../../common/api'; import { CASE_SAVED_OBJECT, SUB_CASE_SAVED_OBJECT } from '../../../../saved_object_types'; import { buildCommentUserActionItem } from '../../../../services/user_actions/helpers'; import { RouteDeps } from '../../types'; import { escapeHatch, wrapError, decodeCommentRequest } from '../../utils'; -import { CASE_COMMENTS_URL } from '../../../../../common'; +import { CASE_COMMENTS_URL } from '../../../../../common/constants'; import { CaseServiceSetup } from '../../../../services'; interface CombinedCaseParams { diff --git a/x-pack/plugins/cases/server/routes/api/cases/comments/post_comment.test.ts b/x-pack/plugins/cases/server/routes/api/cases/comments/post_comment.test.ts index 27d5c47d4739..807ec0d089a5 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/comments/post_comment.test.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/comments/post_comment.test.ts @@ -17,8 +17,8 @@ import { mockCaseComments, } from '../../__fixtures__'; import { initPostCommentApi } from './post_comment'; -import { CASE_COMMENTS_URL } from '../../../../../common'; -import { CommentType } from '../../../../../common'; +import { CASE_COMMENTS_URL } from '../../../../../common/constants'; +import { CommentType } from '../../../../../common/api'; describe('POST comment', () => { let routeHandler: RequestHandler<any, any, any>; diff --git a/x-pack/plugins/cases/server/routes/api/cases/comments/post_comment.ts b/x-pack/plugins/cases/server/routes/api/cases/comments/post_comment.ts index 47d41b60165d..110a16a61001 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/comments/post_comment.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/comments/post_comment.ts @@ -8,8 +8,8 @@ import { schema } from '@kbn/config-schema'; import { escapeHatch, wrapError } from '../../utils'; import { RouteDeps } from '../../types'; -import { CASE_COMMENTS_URL } from '../../../../../common'; -import { CommentRequest } from '../../../../../common'; +import { CASE_COMMENTS_URL } from '../../../../../common/constants'; +import { CommentRequest } from '../../../../../common/api'; export function initPostCommentApi({ router, logger }: RouteDeps) { router.post( diff --git a/x-pack/plugins/cases/server/routes/api/cases/configure/get_configure.test.ts b/x-pack/plugins/cases/server/routes/api/cases/configure/get_configure.test.ts index 626f53cdf426..f328844acfd0 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/configure/get_configure.test.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/configure/get_configure.test.ts @@ -17,8 +17,9 @@ import { } from '../../__fixtures__'; import { initGetCaseConfigure } from './get_configure'; -import { CASE_CONFIGURE_URL, ConnectorTypes } from '../../../../../common'; +import { CASE_CONFIGURE_URL } from '../../../../../common/constants'; import { mappings } from '../../../../client/configure/mock'; +import { ConnectorTypes } from '../../../../../common/api/connectors'; import { CasesClient } from '../../../../client'; describe('GET configuration', () => { diff --git a/x-pack/plugins/cases/server/routes/api/cases/configure/get_configure.ts b/x-pack/plugins/cases/server/routes/api/cases/configure/get_configure.ts index 03ac3dd8b13b..c916bd8f4140 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/configure/get_configure.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/configure/get_configure.ts @@ -6,10 +6,10 @@ */ import Boom from '@hapi/boom'; -import { CaseConfigureResponseRt, ConnectorMappingsAttributes } from '../../../../../common'; +import { CaseConfigureResponseRt, ConnectorMappingsAttributes } from '../../../../../common/api'; import { RouteDeps } from '../../types'; import { wrapError } from '../../utils'; -import { CASE_CONFIGURE_URL } from '../../../../../common'; +import { CASE_CONFIGURE_URL } from '../../../../../common/constants'; import { transformESConnectorToCaseConnector } from '../helpers'; export function initGetCaseConfigure({ caseConfigureService, router, logger }: RouteDeps) { diff --git a/x-pack/plugins/cases/server/routes/api/cases/configure/get_connectors.test.ts b/x-pack/plugins/cases/server/routes/api/cases/configure/get_connectors.test.ts index 082adf7b4803..3fa0fe2f83f7 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/configure/get_connectors.test.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/configure/get_connectors.test.ts @@ -17,7 +17,7 @@ import { } from '../../__fixtures__'; import { initCaseConfigureGetActionConnector } from './get_connectors'; -import { CASE_CONFIGURE_CONNECTORS_URL } from '../../../../../common'; +import { CASE_CONFIGURE_CONNECTORS_URL } from '../../../../../common/constants'; import { getActions } from '../../__mocks__/request_responses'; describe('GET connectors', () => { diff --git a/x-pack/plugins/cases/server/routes/api/cases/configure/get_connectors.ts b/x-pack/plugins/cases/server/routes/api/cases/configure/get_connectors.ts index 7aec7e4f086b..81ffc06355ff 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/configure/get_connectors.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/configure/get_connectors.ts @@ -12,7 +12,10 @@ import { ActionType } from '../../../../../../actions/common'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { FindActionResult } from '../../../../../../actions/server/types'; -import { CASE_CONFIGURE_CONNECTORS_URL, SUPPORTED_CONNECTORS } from '../../../../../common'; +import { + CASE_CONFIGURE_CONNECTORS_URL, + SUPPORTED_CONNECTORS, +} from '../../../../../common/constants'; const isConnectorSupported = ( action: FindActionResult, diff --git a/x-pack/plugins/cases/server/routes/api/cases/configure/patch_configure.test.ts b/x-pack/plugins/cases/server/routes/api/cases/configure/patch_configure.test.ts index c4e2b6af1cd6..48d88e0f622f 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/configure/patch_configure.test.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/configure/patch_configure.test.ts @@ -17,7 +17,8 @@ import { import { mockCaseConfigure } from '../../__fixtures__/mock_saved_objects'; import { initPatchCaseConfigure } from './patch_configure'; -import { CASE_CONFIGURE_URL, ConnectorTypes } from '../../../../../common'; +import { CASE_CONFIGURE_URL } from '../../../../../common/constants'; +import { ConnectorTypes } from '../../../../../common/api/connectors'; import { CasesClient } from '../../../../client'; describe('PATCH configuration', () => { diff --git a/x-pack/plugins/cases/server/routes/api/cases/configure/patch_configure.ts b/x-pack/plugins/cases/server/routes/api/cases/configure/patch_configure.ts index 5fe38cf0efe4..ba0ea6eb1793 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/configure/patch_configure.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/configure/patch_configure.ts @@ -15,10 +15,10 @@ import { CaseConfigureResponseRt, throwErrors, ConnectorMappingsAttributes, -} from '../../../../../common'; +} from '../../../../../common/api'; import { RouteDeps } from '../../types'; import { wrapError, escapeHatch } from '../../utils'; -import { CASE_CONFIGURE_URL } from '../../../../../common'; +import { CASE_CONFIGURE_URL } from '../../../../../common/constants'; import { transformCaseConnectorToEsConnector, transformESConnectorToCaseConnector, diff --git a/x-pack/plugins/cases/server/routes/api/cases/configure/post_configure.test.ts b/x-pack/plugins/cases/server/routes/api/cases/configure/post_configure.test.ts index 35b662078fe9..882a10742d73 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/configure/post_configure.test.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/configure/post_configure.test.ts @@ -18,7 +18,8 @@ import { import { initPostCaseConfigure } from './post_configure'; import { newConfiguration } from '../../__mocks__/request_responses'; -import { CASE_CONFIGURE_URL, ConnectorTypes } from '../../../../../common'; +import { CASE_CONFIGURE_URL } from '../../../../../common/constants'; +import { ConnectorTypes } from '../../../../../common/api/connectors'; import { CasesClient } from '../../../../client'; describe('POST configuration', () => { diff --git a/x-pack/plugins/cases/server/routes/api/cases/configure/post_configure.ts b/x-pack/plugins/cases/server/routes/api/cases/configure/post_configure.ts index 74ad02f47e17..469151a12689 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/configure/post_configure.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/configure/post_configure.ts @@ -15,10 +15,10 @@ import { CaseConfigureResponseRt, throwErrors, ConnectorMappingsAttributes, -} from '../../../../../common'; +} from '../../../../../common/api'; import { RouteDeps } from '../../types'; import { wrapError, escapeHatch } from '../../utils'; -import { CASE_CONFIGURE_URL } from '../../../../../common'; +import { CASE_CONFIGURE_URL } from '../../../../../common/constants'; import { transformCaseConnectorToEsConnector, transformESConnectorToCaseConnector, diff --git a/x-pack/plugins/cases/server/routes/api/cases/delete_cases.test.ts b/x-pack/plugins/cases/server/routes/api/cases/delete_cases.test.ts index 7748a079ceb4..a441a027769b 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/delete_cases.test.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/delete_cases.test.ts @@ -17,7 +17,7 @@ import { mockCaseComments, } from '../__fixtures__'; import { initDeleteCasesApi } from './delete_cases'; -import { CASES_URL } from '../../../../common'; +import { CASES_URL } from '../../../../common/constants'; describe('DELETE case', () => { let routeHandler: RequestHandler<any, any, any>; diff --git a/x-pack/plugins/cases/server/routes/api/cases/delete_cases.ts b/x-pack/plugins/cases/server/routes/api/cases/delete_cases.ts index 43710dfab93e..5f2a6c67220c 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/delete_cases.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/delete_cases.ts @@ -11,7 +11,7 @@ import { SavedObjectsClientContract } from 'src/core/server'; import { buildCaseUserActionItem } from '../../../services/user_actions/helpers'; import { RouteDeps } from '../types'; import { wrapError } from '../utils'; -import { CASES_URL } from '../../../../common'; +import { CASES_URL } from '../../../../common/constants'; import { CaseServiceSetup } from '../../../services'; async function deleteSubCases({ diff --git a/x-pack/plugins/cases/server/routes/api/cases/find_cases.test.ts b/x-pack/plugins/cases/server/routes/api/cases/find_cases.test.ts index 75586896390f..ca9f731ca501 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/find_cases.test.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/find_cases.test.ts @@ -15,7 +15,7 @@ import { mockCases, } from '../__fixtures__'; import { initFindCasesApi } from './find_cases'; -import { CASES_URL } from '../../../../common'; +import { CASES_URL } from '../../../../common/constants'; import { mockCaseConfigure, mockCaseNoConnectorId } from '../__fixtures__/mock_saved_objects'; describe('FIND all cases', () => { diff --git a/x-pack/plugins/cases/server/routes/api/cases/find_cases.ts b/x-pack/plugins/cases/server/routes/api/cases/find_cases.ts index 97455e9e08f7..bc6907f52b9e 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/find_cases.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/find_cases.ts @@ -16,10 +16,10 @@ import { CasesFindRequestRt, throwErrors, caseStatuses, -} from '../../../../common'; +} from '../../../../common/api'; import { transformCases, wrapError, escapeHatch } from '../utils'; import { RouteDeps } from '../types'; -import { CASES_URL } from '../../../../common'; +import { CASES_URL } from '../../../../common/constants'; import { constructQueryOptions } from './helpers'; export function initFindCasesApi({ caseService, router, logger }: RouteDeps) { diff --git a/x-pack/plugins/cases/server/routes/api/cases/get_case.test.ts b/x-pack/plugins/cases/server/routes/api/cases/get_case.test.ts index 768bbca62f3f..b9312331b4df 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/get_case.test.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/get_case.test.ts @@ -8,7 +8,7 @@ import { kibanaResponseFactory, RequestHandler, SavedObject } from 'src/core/server'; import { httpServerMock } from 'src/core/server/mocks'; -import { ConnectorTypes, ESCaseAttributes } from '../../../../common'; +import { ConnectorTypes, ESCaseAttributes } from '../../../../common/api'; import { createMockSavedObjectsRepository, createRoute, @@ -21,7 +21,7 @@ import { } from '../__fixtures__'; import { flattenCaseSavedObject } from '../utils'; import { initGetCaseApi } from './get_case'; -import { CASE_DETAILS_URL } from '../../../../common'; +import { CASE_DETAILS_URL } from '../../../../common/constants'; describe('GET case', () => { let routeHandler: RequestHandler<any, any, any>; diff --git a/x-pack/plugins/cases/server/routes/api/cases/get_case.ts b/x-pack/plugins/cases/server/routes/api/cases/get_case.ts index e2d08dcd23f2..f464f7e47fe7 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/get_case.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/get_case.ts @@ -9,7 +9,7 @@ import { schema } from '@kbn/config-schema'; import { RouteDeps } from '../types'; import { wrapError } from '../utils'; -import { CASE_DETAILS_URL } from '../../../../common'; +import { CASE_DETAILS_URL } from '../../../../common/constants'; export function initGetCaseApi({ router, logger }: RouteDeps) { router.get( diff --git a/x-pack/plugins/cases/server/routes/api/cases/helpers.test.ts b/x-pack/plugins/cases/server/routes/api/cases/helpers.test.ts index a1d25aa29579..f7cfebeaea74 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/helpers.test.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/helpers.test.ts @@ -11,7 +11,7 @@ import { ConnectorTypes, ESCaseConnector, ESCasesConfigureAttributes, -} from '../../../../common'; +} from '../../../../common/api'; import { mockCaseConfigure } from '../__fixtures__'; import { transformCaseConnectorToEsConnector, diff --git a/x-pack/plugins/cases/server/routes/api/cases/helpers.ts b/x-pack/plugins/cases/server/routes/api/cases/helpers.ts index 5f51c9b1f8d8..8659ab02d6d5 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/helpers.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/helpers.ts @@ -11,15 +11,14 @@ import deepEqual from 'fast-deep-equal'; import { SavedObjectsFindResponse } from 'kibana/server'; import { CaseConnector, - CaseStatuses, - CaseType, - ConnectorTypeFields, - ConnectorTypes, ESCaseConnector, ESCasesConfigureAttributes, - ESConnectorFields, + ConnectorTypes, + CaseStatuses, + CaseType, SavedObjectFindOptions, -} from '../../../../common'; +} from '../../../../common/api'; +import { ESConnectorFields, ConnectorTypeFields } from '../../../../common/api/connectors'; import { CASE_SAVED_OBJECT, SUB_CASE_SAVED_OBJECT } from '../../../saved_object_types'; import { sortToSnake } from '../utils'; import { combineFilters } from '../../../common'; diff --git a/x-pack/plugins/cases/server/routes/api/cases/patch_cases.test.ts b/x-pack/plugins/cases/server/routes/api/cases/patch_cases.test.ts index 96a891441ea5..b3f87211c954 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/patch_cases.test.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/patch_cases.test.ts @@ -17,7 +17,7 @@ import { } from '../__fixtures__'; import { initPatchCasesApi } from './patch_cases'; import { mockCaseConfigure, mockCaseNoConnectorId } from '../__fixtures__/mock_saved_objects'; -import { CaseStatuses } from '../../../../common'; +import { CaseStatuses } from '../../../../common/api'; describe('PATCH cases', () => { let routeHandler: RequestHandler<any, any, any>; diff --git a/x-pack/plugins/cases/server/routes/api/cases/patch_cases.ts b/x-pack/plugins/cases/server/routes/api/cases/patch_cases.ts index 092f88c1a8a2..8e779087bcaf 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/patch_cases.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/patch_cases.ts @@ -7,8 +7,8 @@ import { escapeHatch, wrapError } from '../utils'; import { RouteDeps } from '../types'; -import { CASES_URL } from '../../../../common'; -import { CasesPatchRequest } from '../../../../common'; +import { CASES_URL } from '../../../../common/constants'; +import { CasesPatchRequest } from '../../../../common/api'; export function initPatchCasesApi({ router, logger }: RouteDeps) { router.patch( diff --git a/x-pack/plugins/cases/server/routes/api/cases/post_case.test.ts b/x-pack/plugins/cases/server/routes/api/cases/post_case.test.ts index 669d3a5e5887..e1669203d3de 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/post_case.test.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/post_case.test.ts @@ -15,9 +15,9 @@ import { mockCases, } from '../__fixtures__'; import { initPostCaseApi } from './post_case'; -import { CASES_URL } from '../../../../common'; +import { CASES_URL } from '../../../../common/constants'; import { mockCaseConfigure } from '../__fixtures__/mock_saved_objects'; -import { ConnectorTypes, CaseStatuses } from '../../../../common'; +import { ConnectorTypes, CaseStatuses } from '../../../../common/api'; describe('POST cases', () => { let routeHandler: RequestHandler<any, any, any>; diff --git a/x-pack/plugins/cases/server/routes/api/cases/post_case.ts b/x-pack/plugins/cases/server/routes/api/cases/post_case.ts index a7951a1a7134..e2d71c583735 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/post_case.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/post_case.ts @@ -8,8 +8,8 @@ import { wrapError, escapeHatch } from '../utils'; import { RouteDeps } from '../types'; -import { CASES_URL } from '../../../../common'; -import { CasePostRequest } from '../../../../common'; +import { CASES_URL } from '../../../../common/constants'; +import { CasePostRequest } from '../../../../common/api'; export function initPostCaseApi({ router, logger }: RouteDeps) { router.post( diff --git a/x-pack/plugins/cases/server/routes/api/cases/push_case.test.ts b/x-pack/plugins/cases/server/routes/api/cases/push_case.test.ts index 378d092c8be0..fb0ba5e3b5d9 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/push_case.test.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/push_case.test.ts @@ -20,7 +20,7 @@ import { } from '../__fixtures__'; import { initPushCaseApi } from './push_case'; import { CasesRequestHandlerContext } from '../../../types'; -import { getCasePushUrl } from '../../../../common'; +import { getCasePushUrl } from '../../../../common/api/helpers'; describe('Push case', () => { let routeHandler: RequestHandler<any, any, any>; diff --git a/x-pack/plugins/cases/server/routes/api/cases/push_case.ts b/x-pack/plugins/cases/server/routes/api/cases/push_case.ts index 9bfb30e0d63a..7395758210cf 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/push_case.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/push_case.ts @@ -12,9 +12,9 @@ import { identity } from 'fp-ts/lib/function'; import { wrapError, escapeHatch } from '../utils'; -import { throwErrors, CasePushRequestParamsRt } from '../../../../common'; +import { throwErrors, CasePushRequestParamsRt } from '../../../../common/api'; import { RouteDeps } from '../types'; -import { CASE_PUSH_URL } from '../../../../common'; +import { CASE_PUSH_URL } from '../../../../common/constants'; export function initPushCaseApi({ router, logger }: RouteDeps) { router.post( diff --git a/x-pack/plugins/cases/server/routes/api/cases/reporters/get_reporters.ts b/x-pack/plugins/cases/server/routes/api/cases/reporters/get_reporters.ts index 53fdc298ef26..e5433f497223 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/reporters/get_reporters.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/reporters/get_reporters.ts @@ -5,10 +5,10 @@ * 2.0. */ -import { UsersRt } from '../../../../../common'; +import { UsersRt } from '../../../../../common/api'; import { RouteDeps } from '../../types'; import { wrapError } from '../../utils'; -import { CASE_REPORTERS_URL } from '../../../../../common'; +import { CASE_REPORTERS_URL } from '../../../../../common/constants'; export function initGetReportersApi({ caseService, router, logger }: RouteDeps) { router.get( diff --git a/x-pack/plugins/cases/server/routes/api/cases/status/get_status.test.ts b/x-pack/plugins/cases/server/routes/api/cases/status/get_status.test.ts index 60ad0c60f944..1c399a415e47 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/status/get_status.test.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/status/get_status.test.ts @@ -15,8 +15,8 @@ import { mockCases, } from '../../__fixtures__'; import { initGetCasesStatusApi } from './get_status'; -import { CASE_STATUS_URL } from '../../../../../common'; -import { CaseType } from '../../../../../common'; +import { CASE_STATUS_URL } from '../../../../../common/constants'; +import { CaseType } from '../../../../../common/api'; describe('GET status', () => { let routeHandler: RequestHandler<any, any, any>; diff --git a/x-pack/plugins/cases/server/routes/api/cases/status/get_status.ts b/x-pack/plugins/cases/server/routes/api/cases/status/get_status.ts index 73642fdee0ea..d0addfff0912 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/status/get_status.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/status/get_status.ts @@ -8,8 +8,8 @@ import { RouteDeps } from '../../types'; import { wrapError } from '../../utils'; -import { CasesStatusResponseRt, caseStatuses } from '../../../../../common'; -import { CASE_STATUS_URL } from '../../../../../common'; +import { CasesStatusResponseRt, caseStatuses } from '../../../../../common/api'; +import { CASE_STATUS_URL } from '../../../../../common/constants'; import { constructQueryOptions } from '../helpers'; export function initGetCasesStatusApi({ caseService, router, logger }: RouteDeps) { diff --git a/x-pack/plugins/cases/server/routes/api/cases/sub_case/delete_sub_cases.ts b/x-pack/plugins/cases/server/routes/api/cases/sub_case/delete_sub_cases.ts index ef60c743ec82..fd33afbd7df8 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/sub_case/delete_sub_cases.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/sub_case/delete_sub_cases.ts @@ -10,7 +10,7 @@ import { schema } from '@kbn/config-schema'; import { buildCaseUserActionItem } from '../../../../services/user_actions/helpers'; import { RouteDeps } from '../../types'; import { wrapError } from '../../utils'; -import { SUB_CASES_PATCH_DEL_URL } from '../../../../../common'; +import { SUB_CASES_PATCH_DEL_URL } from '../../../../../common/constants'; import { CASE_SAVED_OBJECT } from '../../../../saved_object_types'; export function initDeleteSubCasesApi({ diff --git a/x-pack/plugins/cases/server/routes/api/cases/sub_case/find_sub_cases.ts b/x-pack/plugins/cases/server/routes/api/cases/sub_case/find_sub_cases.ts index 81d5517b8ce5..c24dde1944f8 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/sub_case/find_sub_cases.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/sub_case/find_sub_cases.ts @@ -17,10 +17,10 @@ import { SubCasesFindRequestRt, SubCasesFindResponseRt, throwErrors, -} from '../../../../../common'; +} from '../../../../../common/api'; import { RouteDeps } from '../../types'; import { escapeHatch, transformSubCases, wrapError } from '../../utils'; -import { SUB_CASES_URL } from '../../../../../common'; +import { SUB_CASES_URL } from '../../../../../common/constants'; import { constructQueryOptions } from '../helpers'; import { defaultPage, defaultPerPage } from '../..'; diff --git a/x-pack/plugins/cases/server/routes/api/cases/sub_case/get_sub_case.ts b/x-pack/plugins/cases/server/routes/api/cases/sub_case/get_sub_case.ts index b5ebfb4de348..32dcc924e1a0 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/sub_case/get_sub_case.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/sub_case/get_sub_case.ts @@ -7,10 +7,10 @@ import { schema } from '@kbn/config-schema'; -import { SubCaseResponseRt } from '../../../../../common'; +import { SubCaseResponseRt } from '../../../../../common/api'; import { RouteDeps } from '../../types'; import { flattenSubCaseSavedObject, wrapError } from '../../utils'; -import { SUB_CASE_DETAILS_URL } from '../../../../../common'; +import { SUB_CASE_DETAILS_URL } from '../../../../../common/constants'; import { countAlertsForID } from '../../../../common'; export function initGetSubCaseApi({ caseService, router, logger }: RouteDeps) { diff --git a/x-pack/plugins/cases/server/routes/api/cases/sub_case/patch_sub_cases.ts b/x-pack/plugins/cases/server/routes/api/cases/sub_case/patch_sub_cases.ts index 0b142fb5279e..08836615e1d3 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/sub_case/patch_sub_cases.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/sub_case/patch_sub_cases.ts @@ -35,8 +35,8 @@ import { SubCasesResponseRt, User, CommentAttributes, -} from '../../../../../common'; -import { SUB_CASES_PATCH_DEL_URL } from '../../../../../common'; +} from '../../../../../common/api'; +import { SUB_CASES_PATCH_DEL_URL } from '../../../../../common/constants'; import { RouteDeps } from '../../types'; import { escapeHatch, diff --git a/x-pack/plugins/cases/server/routes/api/cases/tags/get_tags.ts b/x-pack/plugins/cases/server/routes/api/cases/tags/get_tags.ts index d70d6e0b57ee..f066aa70ec47 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/tags/get_tags.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/tags/get_tags.ts @@ -7,7 +7,7 @@ import { RouteDeps } from '../../types'; import { wrapError } from '../../utils'; -import { CASE_TAGS_URL } from '../../../../../common'; +import { CASE_TAGS_URL } from '../../../../../common/constants'; export function initGetTagsApi({ caseService, router }: RouteDeps) { router.get( diff --git a/x-pack/plugins/cases/server/routes/api/cases/user_actions/get_all_user_actions.ts b/x-pack/plugins/cases/server/routes/api/cases/user_actions/get_all_user_actions.ts index 48393b6af34a..b5c564648c18 100644 --- a/x-pack/plugins/cases/server/routes/api/cases/user_actions/get_all_user_actions.ts +++ b/x-pack/plugins/cases/server/routes/api/cases/user_actions/get_all_user_actions.ts @@ -9,7 +9,7 @@ import { schema } from '@kbn/config-schema'; import { RouteDeps } from '../../types'; import { wrapError } from '../../utils'; -import { CASE_USER_ACTIONS_URL, SUB_CASE_USER_ACTIONS_URL } from '../../../../../common'; +import { CASE_USER_ACTIONS_URL, SUB_CASE_USER_ACTIONS_URL } from '../../../../../common/constants'; export function initGetAllCaseUserActionsApi({ router, logger }: RouteDeps) { router.get( diff --git a/x-pack/plugins/cases/server/routes/api/utils.test.ts b/x-pack/plugins/cases/server/routes/api/utils.test.ts index 2df17e3abacf..f6bc1e4f7189 100644 --- a/x-pack/plugins/cases/server/routes/api/utils.test.ts +++ b/x-pack/plugins/cases/server/routes/api/utils.test.ts @@ -30,7 +30,7 @@ import { AssociationType, CaseType, CaseResponse, -} from '../../../common'; +} from '../../../common/api'; describe('Utils', () => { describe('transformNewCase', () => { diff --git a/x-pack/plugins/cases/server/routes/api/utils.ts b/x-pack/plugins/cases/server/routes/api/utils.ts index 9234472c13f5..8e8862f4157f 100644 --- a/x-pack/plugins/cases/server/routes/api/utils.ts +++ b/x-pack/plugins/cases/server/routes/api/utils.ts @@ -41,7 +41,7 @@ import { SubCasesFindResponse, User, AlertCommentRequestRt, -} from '../../../common'; +} from '../../../common/api'; import { transformESConnectorToCaseConnector } from './cases/helpers'; import { SortFieldCase } from './types'; diff --git a/x-pack/plugins/cases/server/saved_object_types/migrations.ts b/x-pack/plugins/cases/server/saved_object_types/migrations.ts index 8bbc48112487..bf9694d7e6bb 100644 --- a/x-pack/plugins/cases/server/saved_object_types/migrations.ts +++ b/x-pack/plugins/cases/server/saved_object_types/migrations.ts @@ -14,7 +14,7 @@ import { CaseType, AssociationType, ESConnectorFields, -} from '../../common'; +} from '../../common/api'; interface UnsanitizedCaseConnector { connector_id: string; diff --git a/x-pack/plugins/cases/server/scripts/sub_cases/index.ts b/x-pack/plugins/cases/server/scripts/sub_cases/index.ts index 56f842c10e8f..ba3bcaa65091 100644 --- a/x-pack/plugins/cases/server/scripts/sub_cases/index.ts +++ b/x-pack/plugins/cases/server/scripts/sub_cases/index.ts @@ -8,7 +8,9 @@ import yargs from 'yargs'; import { ToolingLog } from '@kbn/dev-utils'; import { KbnClient } from '@kbn/test'; -import { CaseResponse, CaseType, CommentType, ConnectorTypes, CASES_URL } from '../../../common'; +import { CaseResponse, CaseType, ConnectorTypes } from '../../../common/api'; +import { CommentType } from '../../../common/api/cases/comment'; +import { CASES_URL } from '../../../common/constants'; import { ActionResult, ActionTypeExecutorResult } from '../../../../actions/common'; import { ContextTypeGeneratedAlertType, createAlertsString } from '../../connectors'; diff --git a/x-pack/plugins/cases/server/services/alerts/index.test.ts b/x-pack/plugins/cases/server/services/alerts/index.test.ts index 28c3a6278d54..042e415b77e4 100644 --- a/x-pack/plugins/cases/server/services/alerts/index.test.ts +++ b/x-pack/plugins/cases/server/services/alerts/index.test.ts @@ -6,7 +6,7 @@ */ import { KibanaRequest } from 'kibana/server'; -import { CaseStatuses } from '../../../common'; +import { CaseStatuses } from '../../../common/api'; import { AlertService, AlertServiceContract } from '.'; import { elasticsearchServiceMock, loggingSystemMock } from 'src/core/server/mocks'; diff --git a/x-pack/plugins/cases/server/services/alerts/index.ts b/x-pack/plugins/cases/server/services/alerts/index.ts index 876814719442..6ce4db61ab95 100644 --- a/x-pack/plugins/cases/server/services/alerts/index.ts +++ b/x-pack/plugins/cases/server/services/alerts/index.ts @@ -10,7 +10,7 @@ import { isEmpty } from 'lodash'; import type { PublicMethodsOf } from '@kbn/utility-types'; import { ElasticsearchClient, Logger } from 'kibana/server'; -import { MAX_ALERTS_PER_SUB_CASE } from '../../../common'; +import { MAX_ALERTS_PER_SUB_CASE } from '../../../common/constants'; import { UpdateAlertRequest } from '../../client/types'; import { AlertInfo } from '../../common'; import { createCaseError } from '../../common/error'; diff --git a/x-pack/plugins/cases/server/services/configure/index.ts b/x-pack/plugins/cases/server/services/configure/index.ts index 0ca63bce2d1d..46dca4d9a0d0 100644 --- a/x-pack/plugins/cases/server/services/configure/index.ts +++ b/x-pack/plugins/cases/server/services/configure/index.ts @@ -13,7 +13,7 @@ import { SavedObjectsUpdateResponse, } from 'kibana/server'; -import { ESCasesConfigureAttributes, SavedObjectFindOptions } from '../../../common'; +import { ESCasesConfigureAttributes, SavedObjectFindOptions } from '../../../common/api'; import { CASE_CONFIGURE_SAVED_OBJECT } from '../../saved_object_types'; interface ClientArgs { diff --git a/x-pack/plugins/cases/server/services/connector_mappings/index.ts b/x-pack/plugins/cases/server/services/connector_mappings/index.ts index 82f37190b4ec..d4fda10276d2 100644 --- a/x-pack/plugins/cases/server/services/connector_mappings/index.ts +++ b/x-pack/plugins/cases/server/services/connector_mappings/index.ts @@ -13,7 +13,7 @@ import { SavedObjectsFindResponse, } from 'kibana/server'; -import { ConnectorMappings, SavedObjectFindOptions } from '../../../common'; +import { ConnectorMappings, SavedObjectFindOptions } from '../../../common/api'; import { CASE_CONNECTOR_MAPPINGS_SAVED_OBJECT } from '../../saved_object_types'; interface ClientArgs { diff --git a/x-pack/plugins/cases/server/services/index.ts b/x-pack/plugins/cases/server/services/index.ts index 18b78300e663..11ceb48d11e9 100644 --- a/x-pack/plugins/cases/server/services/index.ts +++ b/x-pack/plugins/cases/server/services/index.ts @@ -33,7 +33,7 @@ import { CaseResponse, caseTypeField, CasesFindRequest, -} from '../../common'; +} from '../../common/api'; import { combineFilters, defaultSortField, groupTotalAlertsByID } from '../common'; import { defaultPage, defaultPerPage } from '../routes/api'; import { diff --git a/x-pack/plugins/cases/server/services/reporters/read_reporters.ts b/x-pack/plugins/cases/server/services/reporters/read_reporters.ts index b47fa185ff78..d2708780b2cc 100644 --- a/x-pack/plugins/cases/server/services/reporters/read_reporters.ts +++ b/x-pack/plugins/cases/server/services/reporters/read_reporters.ts @@ -7,7 +7,7 @@ import { SavedObject, SavedObjectsClientContract } from 'kibana/server'; -import { CaseAttributes, User } from '../../../common'; +import { CaseAttributes, User } from '../../../common/api'; import { CASE_SAVED_OBJECT } from '../../saved_object_types'; export const convertToReporters = (caseObjects: Array<SavedObject<CaseAttributes>>): User[] => diff --git a/x-pack/plugins/cases/server/services/tags/read_tags.ts b/x-pack/plugins/cases/server/services/tags/read_tags.ts index a00b0b6f26fb..4c4a94845373 100644 --- a/x-pack/plugins/cases/server/services/tags/read_tags.ts +++ b/x-pack/plugins/cases/server/services/tags/read_tags.ts @@ -7,7 +7,7 @@ import { SavedObject, SavedObjectsClientContract } from 'kibana/server'; -import { CaseAttributes } from '../../../common'; +import { CaseAttributes } from '../../../common/api'; import { CASE_SAVED_OBJECT } from '../../saved_object_types'; export const convertToTags = (tagObjects: Array<SavedObject<CaseAttributes>>): string[] => diff --git a/x-pack/plugins/cases/server/services/user_actions/helpers.ts b/x-pack/plugins/cases/server/services/user_actions/helpers.ts index be32717039d9..c600a96234b3 100644 --- a/x-pack/plugins/cases/server/services/user_actions/helpers.ts +++ b/x-pack/plugins/cases/server/services/user_actions/helpers.ts @@ -17,7 +17,7 @@ import { User, UserActionFieldType, SubCaseAttributes, -} from '../../../common'; +} from '../../../common/api'; import { isTwoArraysDifference, transformESConnectorToCaseConnector, diff --git a/x-pack/plugins/cases/server/services/user_actions/index.ts b/x-pack/plugins/cases/server/services/user_actions/index.ts index a038d843a533..785c81021b58 100644 --- a/x-pack/plugins/cases/server/services/user_actions/index.ts +++ b/x-pack/plugins/cases/server/services/user_actions/index.ts @@ -12,7 +12,7 @@ import { SavedObjectReference, } from 'kibana/server'; -import { CaseUserActionAttributes } from '../../../common'; +import { CaseUserActionAttributes } from '../../../common/api'; import { CASE_USER_ACTION_SAVED_OBJECT, CASE_SAVED_OBJECT, diff --git a/x-pack/plugins/security_solution/common/constants.ts b/x-pack/plugins/security_solution/common/constants.ts index 47606983b836..143384d16047 100644 --- a/x-pack/plugins/security_solution/common/constants.ts +++ b/x-pack/plugins/security_solution/common/constants.ts @@ -23,8 +23,6 @@ export const DEFAULT_REFRESH_RATE_INTERVAL = 'timepicker:refreshIntervalDefaults export const DEFAULT_APP_TIME_RANGE = 'securitySolution:timeDefaults'; export const DEFAULT_APP_REFRESH_INTERVAL = 'securitySolution:refreshIntervalDefaults'; export const DEFAULT_SIGNALS_INDEX = '.siem-signals'; -// The DEFAULT_MAX_SIGNALS value exists also in `x-pack/plugins/cases/common/constants.ts` -// If either changes, engineer should ensure both values are updated export const DEFAULT_MAX_SIGNALS = 100; export const DEFAULT_SEARCH_AFTER_PAGE_SIZE = 100; export const DEFAULT_ANOMALY_SCORE = 'securitySolution:defaultAnomalyScore'; @@ -208,10 +206,3 @@ export const showAllOthersBucket: string[] = [ 'destination.ip', 'user.name', ]; - -/* - Feature Flag for Cases RAC UI - DO NOT MERGE to master as true, dev only -*/ - -export const USE_RAC_CASES_UI = false; diff --git a/x-pack/plugins/security_solution/kibana.json b/x-pack/plugins/security_solution/kibana.json index 50a5f6274027..d4551f76ae39 100644 --- a/x-pack/plugins/security_solution/kibana.json +++ b/x-pack/plugins/security_solution/kibana.json @@ -7,7 +7,6 @@ "requiredPlugins": [ "actions", "alerting", - "cases", "data", "dataEnhanced", "embeddable", diff --git a/x-pack/plugins/security_solution/public/cases/components/add_comment/index.test.tsx b/x-pack/plugins/security_solution/public/cases/components/add_comment/index.test.tsx index 6ffce4f2af45..9c06fc032f81 100644 --- a/x-pack/plugins/security_solution/public/cases/components/add_comment/index.test.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/add_comment/index.test.tsx @@ -13,7 +13,7 @@ import { noop } from 'lodash/fp'; import { TestProviders } from '../../../common/mock'; import { Router, routeData, mockHistory, mockLocation } from '../__mock__/router'; -import { CommentRequest, CommentType } from '../../../../../cases/common'; +import { CommentRequest, CommentType } from '../../../../../cases/common/api'; import { useInsertTimeline } from '../use_insert_timeline'; import { usePostComment } from '../../containers/use_post_comment'; import { AddComment, AddCommentRefObject } from '.'; diff --git a/x-pack/plugins/security_solution/public/cases/components/add_comment/index.tsx b/x-pack/plugins/security_solution/public/cases/components/add_comment/index.tsx index ff5ef11fd923..acd27e99a857 100644 --- a/x-pack/plugins/security_solution/public/cases/components/add_comment/index.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/add_comment/index.tsx @@ -9,10 +9,10 @@ import { EuiButton, EuiLoadingSpinner } from '@elastic/eui'; import React, { useCallback, forwardRef, useImperativeHandle } from 'react'; import styled from 'styled-components'; -import { CommentType } from '../../../../../cases/common'; +import { CommentType } from '../../../../../cases/common/api'; import { usePostComment } from '../../containers/use_post_comment'; import { Case } from '../../containers/types'; -import { MarkdownEditorForm } from '../../../common/components/markdown_editor'; +import { MarkdownEditorForm } from '../../../common/components/markdown_editor/eui_form'; import { Form, useForm, UseField, useFormData } from '../../../shared_imports'; import * as i18n from './translations'; diff --git a/x-pack/plugins/security_solution/public/cases/components/add_comment/schema.tsx b/x-pack/plugins/security_solution/public/cases/components/add_comment/schema.tsx index bf625fc06508..2cf7d3c6c555 100644 --- a/x-pack/plugins/security_solution/public/cases/components/add_comment/schema.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/add_comment/schema.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { CommentRequestUserType } from '../../../../../cases/common'; +import { CommentRequestUserType } from '../../../../../cases/common/api'; import { FIELD_TYPES, fieldValidators, FormSchema } from '../../../shared_imports'; import * as i18n from './translations'; diff --git a/x-pack/plugins/security_solution/public/cases/components/all_cases/actions.tsx b/x-pack/plugins/security_solution/public/cases/components/all_cases/actions.tsx index 0353f48e6ee3..daa988641fba 100644 --- a/x-pack/plugins/security_solution/public/cases/components/all_cases/actions.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/all_cases/actions.tsx @@ -8,7 +8,7 @@ import { Dispatch } from 'react'; import { DefaultItemIconButtonAction } from '@elastic/eui/src/components/basic_table/action_types'; -import { CaseStatuses } from '../../../../../cases/common'; +import { CaseStatuses } from '../../../../../cases/common/api'; import { Case, SubCase } from '../../containers/types'; import { UpdateCase } from '../../containers/use_get_cases'; import { statuses } from '../status'; diff --git a/x-pack/plugins/security_solution/public/cases/components/all_cases/columns.tsx b/x-pack/plugins/security_solution/public/cases/components/all_cases/columns.tsx index 079943d8cbd3..86f854fd0a14 100644 --- a/x-pack/plugins/security_solution/public/cases/components/all_cases/columns.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/all_cases/columns.tsx @@ -19,7 +19,7 @@ import { RIGHT_ALIGNMENT } from '@elastic/eui/lib/services'; import styled from 'styled-components'; import { DefaultItemIconButtonAction } from '@elastic/eui/src/components/basic_table/action_types'; -import { CaseStatuses, CaseType } from '../../../../../cases/common'; +import { CaseStatuses, CaseType } from '../../../../../cases/common/api'; import { getEmptyTagValue } from '../../../common/components/empty_value'; import { Case, SubCase } from '../../containers/types'; import { FormattedRelativePreferenceDate } from '../../../common/components/formatted_date'; diff --git a/x-pack/plugins/security_solution/public/cases/components/all_cases/expanded_row.tsx b/x-pack/plugins/security_solution/public/cases/components/all_cases/expanded_row.tsx index f40e159306e9..43f0d9df49e9 100644 --- a/x-pack/plugins/security_solution/public/cases/components/all_cases/expanded_row.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/all_cases/expanded_row.tsx @@ -10,7 +10,7 @@ import { EuiBasicTable as _EuiBasicTable } from '@elastic/eui'; import styled from 'styled-components'; import { Case, SubCase } from '../../containers/types'; import { CasesColumns } from './columns'; -import { AssociationType } from '../../../../../cases/common'; +import { AssociationType } from '../../../../../cases/common/api'; type ExpandedRowMap = Record<string, Element> | {}; diff --git a/x-pack/plugins/security_solution/public/cases/components/all_cases/helpers.ts b/x-pack/plugins/security_solution/public/cases/components/all_cases/helpers.ts index 0d5eb2c9ba40..8962d6731937 100644 --- a/x-pack/plugins/security_solution/public/cases/components/all_cases/helpers.ts +++ b/x-pack/plugins/security_solution/public/cases/components/all_cases/helpers.ts @@ -6,7 +6,7 @@ */ import { filter } from 'lodash/fp'; -import { AssociationType, CaseStatuses, CaseType } from '../../../../../cases/common'; +import { AssociationType, CaseStatuses, CaseType } from '../../../../../cases/common/api'; import { Case, SubCase } from '../../containers/types'; import { statuses } from '../status'; diff --git a/x-pack/plugins/security_solution/public/cases/components/all_cases/index.test.tsx b/x-pack/plugins/security_solution/public/cases/components/all_cases/index.test.tsx index c079bbc99160..0fafdaf81f09 100644 --- a/x-pack/plugins/security_solution/public/cases/components/all_cases/index.test.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/all_cases/index.test.tsx @@ -14,7 +14,7 @@ import { TestProviders } from '../../../common/mock'; import { casesStatus, useGetCasesMockState, collectionCase } from '../../containers/mock'; import * as i18n from './translations'; -import { CaseStatuses, CaseType } from '../../../../../cases/common'; +import { CaseStatuses, CaseType } from '../../../../../cases/common/api'; import { useKibana } from '../../../common/lib/kibana'; import { getEmptyTagValue } from '../../../common/components/empty_value'; import { useDeleteCases } from '../../containers/use_delete_cases'; diff --git a/x-pack/plugins/security_solution/public/cases/components/all_cases/index.tsx b/x-pack/plugins/security_solution/public/cases/components/all_cases/index.tsx index a0820486f423..c5748a321c19 100644 --- a/x-pack/plugins/security_solution/public/cases/components/all_cases/index.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/all_cases/index.tsx @@ -22,7 +22,7 @@ import styled, { css } from 'styled-components'; import classnames from 'classnames'; import * as i18n from './translations'; -import { CaseStatuses, CaseType } from '../../../../../cases/common'; +import { CaseStatuses, CaseType } from '../../../../../cases/common/api'; import { getCasesColumns } from './columns'; import { Case, DeleteCase, FilterOptions, SortFieldCase, SubCase } from '../../containers/types'; import { useGetCases, UpdateCase } from '../../containers/use_get_cases'; diff --git a/x-pack/plugins/security_solution/public/cases/components/all_cases/status_filter.test.tsx b/x-pack/plugins/security_solution/public/cases/components/all_cases/status_filter.test.tsx index f31eda12b339..5c9f11d1e3a8 100644 --- a/x-pack/plugins/security_solution/public/cases/components/all_cases/status_filter.test.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/all_cases/status_filter.test.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { mount } from 'enzyme'; import { waitFor } from '@testing-library/react'; -import { CaseStatuses } from '../../../../../cases/common'; +import { CaseStatuses } from '../../../../../cases/common/api'; import { StatusFilter } from './status_filter'; import { StatusAll } from '../status'; diff --git a/x-pack/plugins/security_solution/public/cases/components/all_cases/table_filters.test.tsx b/x-pack/plugins/security_solution/public/cases/components/all_cases/table_filters.test.tsx index c4486365cd29..48a642aaf51a 100644 --- a/x-pack/plugins/security_solution/public/cases/components/all_cases/table_filters.test.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/all_cases/table_filters.test.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { mount } from 'enzyme'; -import { CaseStatuses } from '../../../../../cases/common'; +import { CaseStatuses } from '../../../../../cases/common/api'; import { TestProviders } from '../../../common/mock'; import { useGetTags } from '../../containers/use_get_tags'; import { useGetReporters } from '../../containers/use_get_reporters'; diff --git a/x-pack/plugins/security_solution/public/cases/components/all_cases/table_filters.tsx b/x-pack/plugins/security_solution/public/cases/components/all_cases/table_filters.tsx index 434ae46fcfb7..ff5b511ef902 100644 --- a/x-pack/plugins/security_solution/public/cases/components/all_cases/table_filters.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/all_cases/table_filters.tsx @@ -10,7 +10,7 @@ import { isEqual } from 'lodash/fp'; import styled from 'styled-components'; import { EuiFlexGroup, EuiFlexItem, EuiFieldSearch, EuiFilterGroup } from '@elastic/eui'; -import { CaseStatuses } from '../../../../../cases/common'; +import { CaseStatuses } from '../../../../../cases/common/api'; import { FilterOptions } from '../../containers/types'; import { useGetTags } from '../../containers/use_get_tags'; import { useGetReporters } from '../../containers/use_get_reporters'; diff --git a/x-pack/plugins/security_solution/public/cases/components/bulk_actions/index.tsx b/x-pack/plugins/security_solution/public/cases/components/bulk_actions/index.tsx index e90ae2b03686..24897a14f075 100644 --- a/x-pack/plugins/security_solution/public/cases/components/bulk_actions/index.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/bulk_actions/index.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { EuiContextMenuItem } from '@elastic/eui'; -import { CaseStatuses } from '../../../../../cases/common'; +import { CaseStatuses } from '../../../../../cases/common/api'; import { statuses, CaseStatusWithAllStatus } from '../status'; import * as i18n from './translations'; import { Case } from '../../containers/types'; diff --git a/x-pack/plugins/security_solution/public/cases/components/case_action_bar/helpers.test.ts b/x-pack/plugins/security_solution/public/cases/components/case_action_bar/helpers.test.ts index 64d37de0a6ea..8e26c0fd7a7f 100644 --- a/x-pack/plugins/security_solution/public/cases/components/case_action_bar/helpers.test.ts +++ b/x-pack/plugins/security_solution/public/cases/components/case_action_bar/helpers.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { CaseStatuses } from '../../../../../cases/common'; +import { CaseStatuses } from '../../../../../cases/common/api'; import { basicCase } from '../../containers/mock'; import { getStatusDate, getStatusTitle } from './helpers'; diff --git a/x-pack/plugins/security_solution/public/cases/components/case_action_bar/helpers.ts b/x-pack/plugins/security_solution/public/cases/components/case_action_bar/helpers.ts index 9dd666c72335..68a243040145 100644 --- a/x-pack/plugins/security_solution/public/cases/components/case_action_bar/helpers.ts +++ b/x-pack/plugins/security_solution/public/cases/components/case_action_bar/helpers.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { CaseStatuses } from '../../../../../cases/common'; +import { CaseStatuses } from '../../../../../cases/common/api'; import { Case } from '../../containers/types'; import { statuses } from '../status'; diff --git a/x-pack/plugins/security_solution/public/cases/components/case_action_bar/index.tsx b/x-pack/plugins/security_solution/public/cases/components/case_action_bar/index.tsx index fd4e49400d46..63ce44173225 100644 --- a/x-pack/plugins/security_solution/public/cases/components/case_action_bar/index.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/case_action_bar/index.tsx @@ -16,7 +16,7 @@ import { EuiFlexItem, EuiIconTip, } from '@elastic/eui'; -import { CaseStatuses, CaseType } from '../../../../../cases/common'; +import { CaseStatuses, CaseType } from '../../../../../cases/common/api'; import * as i18n from '../case_view/translations'; import { FormattedRelativePreferenceDate } from '../../../common/components/formatted_date'; import { Actions } from './actions'; diff --git a/x-pack/plugins/security_solution/public/cases/components/case_action_bar/status_context_menu.test.tsx b/x-pack/plugins/security_solution/public/cases/components/case_action_bar/status_context_menu.test.tsx index 1f3b9c39017d..4e414706d1fd 100644 --- a/x-pack/plugins/security_solution/public/cases/components/case_action_bar/status_context_menu.test.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/case_action_bar/status_context_menu.test.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { mount } from 'enzyme'; -import { CaseStatuses } from '../../../../../cases/common'; +import { CaseStatuses } from '../../../../../cases/common/api'; import { StatusContextMenu } from './status_context_menu'; describe('SyncAlertsSwitch', () => { diff --git a/x-pack/plugins/security_solution/public/cases/components/case_action_bar/status_context_menu.tsx b/x-pack/plugins/security_solution/public/cases/components/case_action_bar/status_context_menu.tsx index 298d0d7695e8..92dcd16a8619 100644 --- a/x-pack/plugins/security_solution/public/cases/components/case_action_bar/status_context_menu.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/case_action_bar/status_context_menu.tsx @@ -8,7 +8,7 @@ import React, { memo, useCallback, useMemo, useState } from 'react'; import { memoize } from 'lodash/fp'; import { EuiPopover, EuiContextMenuPanel, EuiContextMenuItem } from '@elastic/eui'; -import { caseStatuses, CaseStatuses } from '../../../../../cases/common'; +import { caseStatuses, CaseStatuses } from '../../../../../cases/common/api'; import { Status } from '../status'; interface Props { diff --git a/x-pack/plugins/security_solution/public/cases/components/case_view/helpers.test.tsx b/x-pack/plugins/security_solution/public/cases/components/case_view/helpers.test.tsx index 657a19d40fdd..18a76e2766d8 100644 --- a/x-pack/plugins/security_solution/public/cases/components/case_view/helpers.test.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/case_view/helpers.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { AssociationType, CommentType } from '../../../../../cases/common'; +import { AssociationType, CommentType } from '../../../../../cases/common/api'; import { Comment } from '../../containers/types'; import { getManualAlertIdsWithNoRuleId, buildAlertsQuery } from './helpers'; diff --git a/x-pack/plugins/security_solution/public/cases/components/case_view/helpers.ts b/x-pack/plugins/security_solution/public/cases/components/case_view/helpers.ts index 741880d886c8..7211f4bca6a3 100644 --- a/x-pack/plugins/security_solution/public/cases/components/case_view/helpers.ts +++ b/x-pack/plugins/security_solution/public/cases/components/case_view/helpers.ts @@ -6,7 +6,7 @@ */ import { isEmpty } from 'lodash'; -import { CommentType } from '../../../../../cases/common'; +import { CommentType } from '../../../../../cases/common/api'; import { Comment } from '../../containers/types'; export const getManualAlertIdsWithNoRuleId = (comments: Comment[]): string[] => { diff --git a/x-pack/plugins/security_solution/public/cases/components/case_view/index.test.tsx b/x-pack/plugins/security_solution/public/cases/components/case_view/index.test.tsx index 75f91c8ef303..f28c7791d011 100644 --- a/x-pack/plugins/security_solution/public/cases/components/case_view/index.test.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/case_view/index.test.tsx @@ -28,7 +28,8 @@ import { useConnectors } from '../../containers/configure/use_connectors'; import { connectorsMock } from '../../containers/configure/mock'; import { usePostPushToService } from '../../containers/use_post_push_to_service'; import { useQueryAlerts } from '../../../detections/containers/detection_engine/alerts/use_query'; -import { CaseType, ConnectorTypes } from '../../../../../cases/common'; +import { ConnectorTypes } from '../../../../../cases/common/api/connectors'; +import { CaseType } from '../../../../../cases/common/api'; const mockDispatch = jest.fn(); jest.mock('react-redux', () => { diff --git a/x-pack/plugins/security_solution/public/cases/components/case_view/index.tsx b/x-pack/plugins/security_solution/public/cases/components/case_view/index.tsx index e16f1d7683ab..892663c78329 100644 --- a/x-pack/plugins/security_solution/public/cases/components/case_view/index.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/case_view/index.tsx @@ -17,7 +17,7 @@ import { EuiHorizontalRule, } from '@elastic/eui'; -import { CaseStatuses, CaseAttributes, CaseType } from '../../../../../cases/common'; +import { CaseStatuses, CaseAttributes, CaseType } from '../../../../../cases/common/api'; import { Case, CaseConnector } from '../../containers/types'; import { getCaseDetailsUrl, getCaseUrl, useFormatUrl } from '../../../common/components/link_to'; import { gutterTimeline } from '../../../common/lib/helpers'; diff --git a/x-pack/plugins/security_solution/public/cases/components/configure_cases/__mock__/index.tsx b/x-pack/plugins/security_solution/public/cases/components/configure_cases/__mock__/index.tsx index e18e0ef004ce..ccc697a2ae84 100644 --- a/x-pack/plugins/security_solution/public/cases/components/configure_cases/__mock__/index.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/configure_cases/__mock__/index.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { ConnectorTypes } from '../../../../../../cases/common'; +import { ConnectorTypes } from '../../../../../../cases/common/api'; import { ActionConnector } from '../../../containers/configure/types'; import { UseConnectorsResponse } from '../../../containers/configure/use_connectors'; import { ReturnUseCaseConfigure } from '../../../containers/configure/use_configure'; diff --git a/x-pack/plugins/security_solution/public/cases/components/configure_cases/connectors.test.tsx b/x-pack/plugins/security_solution/public/cases/components/configure_cases/connectors.test.tsx index 1c01bb3fdeb7..c34651c3e1dc 100644 --- a/x-pack/plugins/security_solution/public/cases/components/configure_cases/connectors.test.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/configure_cases/connectors.test.tsx @@ -12,7 +12,7 @@ import { Connectors, Props } from './connectors'; import { TestProviders } from '../../../common/mock'; import { ConnectorsDropdown } from './connectors_dropdown'; import { connectors } from './__mock__'; -import { ConnectorTypes } from '../../../../../cases/common'; +import { ConnectorTypes } from '../../../../../cases/common/api/connectors'; describe('Connectors', () => { let wrapper: ReactWrapper; diff --git a/x-pack/plugins/security_solution/public/cases/components/configure_cases/connectors.tsx b/x-pack/plugins/security_solution/public/cases/components/configure_cases/connectors.tsx index c0a5e3c4c8f7..1e0ae95ff901 100644 --- a/x-pack/plugins/security_solution/public/cases/components/configure_cases/connectors.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/configure_cases/connectors.tsx @@ -21,7 +21,7 @@ import * as i18n from './translations'; import { ActionConnector, CaseConnectorMapping } from '../../containers/configure/types'; import { Mapping } from './mapping'; -import { ConnectorTypes } from '../../../../../cases/common'; +import { ConnectorTypes } from '../../../../../cases/common/api/connectors'; const EuiFormRowExtended = styled(EuiFormRow)` .euiFormRow__labelWrapper { diff --git a/x-pack/plugins/security_solution/public/cases/components/configure_cases/connectors_dropdown.tsx b/x-pack/plugins/security_solution/public/cases/components/configure_cases/connectors_dropdown.tsx index 27f7f4d50a0c..01d975a445ab 100644 --- a/x-pack/plugins/security_solution/public/cases/components/configure_cases/connectors_dropdown.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/configure_cases/connectors_dropdown.tsx @@ -9,7 +9,7 @@ import React, { useMemo } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiSuperSelect } from '@elastic/eui'; import styled from 'styled-components'; -import { ConnectorTypes } from '../../../../../cases/common'; +import { ConnectorTypes } from '../../../../../cases/common/api'; import { ActionConnector } from '../../containers/configure/types'; import { connectorsConfiguration } from '../connectors'; import * as i18n from './translations'; diff --git a/x-pack/plugins/security_solution/public/cases/components/configure_cases/index.test.tsx b/x-pack/plugins/security_solution/public/cases/components/configure_cases/index.test.tsx index e78cd4c509d5..8dbefdb73114 100644 --- a/x-pack/plugins/security_solution/public/cases/components/configure_cases/index.test.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/configure_cases/index.test.tsx @@ -33,7 +33,7 @@ import { useConnectorsResponse, useActionTypesResponse, } from './__mock__'; -import { ConnectorTypes } from '../../../../../cases/common'; +import { ConnectorTypes } from '../../../../../cases/common/api/connectors'; jest.mock('../../../common/lib/kibana'); jest.mock('../../containers/configure/use_connectors'); diff --git a/x-pack/plugins/security_solution/public/cases/components/configure_cases/index.tsx b/x-pack/plugins/security_solution/public/cases/components/configure_cases/index.tsx index e951498c6c3c..25155ff77c2d 100644 --- a/x-pack/plugins/security_solution/public/cases/components/configure_cases/index.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/configure_cases/index.tsx @@ -10,7 +10,7 @@ import styled, { css } from 'styled-components'; import { EuiCallOut } from '@elastic/eui'; -import { SUPPORTED_CONNECTORS } from '../../../../../cases/common'; +import { SUPPORTED_CONNECTORS } from '../../../../../cases/common/constants'; import { useKibana } from '../../../common/lib/kibana'; import { useConnectors } from '../../containers/configure/use_connectors'; import { useActionTypes } from '../../containers/configure/use_action_types'; diff --git a/x-pack/plugins/security_solution/public/cases/components/configure_cases/utils.ts b/x-pack/plugins/security_solution/public/cases/components/configure_cases/utils.ts index dfb19250f5bd..db14371b625d 100644 --- a/x-pack/plugins/security_solution/public/cases/components/configure_cases/utils.ts +++ b/x-pack/plugins/security_solution/public/cases/components/configure_cases/utils.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { ConnectorTypeFields, ConnectorTypes } from '../../../../../cases/common'; +import { ConnectorTypeFields, ConnectorTypes } from '../../../../../cases/common/api'; import { CaseField, ActionType, diff --git a/x-pack/plugins/security_solution/public/cases/components/connector_selector/form.tsx b/x-pack/plugins/security_solution/public/cases/components/connector_selector/form.tsx index f0e77648cee6..63c6f265b1ab 100644 --- a/x-pack/plugins/security_solution/public/cases/components/connector_selector/form.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/connector_selector/form.tsx @@ -11,7 +11,7 @@ import { EuiFormRow } from '@elastic/eui'; import { FieldHook, getFieldValidityAndErrorMessage } from '../../../shared_imports'; import { ConnectorsDropdown } from '../configure_cases/connectors_dropdown'; -import { ActionConnector } from '../../../../../cases/common'; +import { ActionConnector } from '../../../../../cases/common/api'; interface ConnectorSelectorProps { connectors: ActionConnector[]; diff --git a/x-pack/plugins/security_solution/public/cases/components/connectors/card.tsx b/x-pack/plugins/security_solution/public/cases/components/connectors/card.tsx index dded090eb3f9..af9a86b0b711 100644 --- a/x-pack/plugins/security_solution/public/cases/components/connectors/card.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/connectors/card.tsx @@ -10,7 +10,7 @@ import { EuiCard, EuiIcon, EuiLoadingSpinner } from '@elastic/eui'; import styled from 'styled-components'; import { connectorsConfiguration } from '.'; -import { ConnectorTypes } from '../../../../../cases/common'; +import { ConnectorTypes } from '../../../../../cases/common/api/connectors'; interface ConnectorCardProps { connectorType: ConnectorTypes; diff --git a/x-pack/plugins/security_solution/public/cases/components/connectors/case/alert_fields.tsx b/x-pack/plugins/security_solution/public/cases/components/connectors/case/alert_fields.tsx index b182c878d78e..05161456976c 100644 --- a/x-pack/plugins/security_solution/public/cases/components/connectors/case/alert_fields.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/connectors/case/alert_fields.tsx @@ -12,7 +12,7 @@ import styled from 'styled-components'; import { EuiCallOut, EuiSpacer } from '@elastic/eui'; import { ActionParamsProps } from '../../../../../../triggers_actions_ui/public/types'; -import { CommentType } from '../../../../../../cases/common'; +import { CommentType } from '../../../../../../cases/common/api'; import { CaseActionParams } from './types'; import { ExistingCase } from './existing_case'; diff --git a/x-pack/plugins/security_solution/public/cases/components/connectors/case/existing_case.tsx b/x-pack/plugins/security_solution/public/cases/components/connectors/case/existing_case.tsx index c503a62ef515..3c6c5f47c6d1 100644 --- a/x-pack/plugins/security_solution/public/cases/components/connectors/case/existing_case.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/connectors/case/existing_case.tsx @@ -6,7 +6,7 @@ */ import React, { memo, useMemo, useCallback } from 'react'; -import { CaseType } from '../../../../../../cases/common'; +import { CaseType } from '../../../../../../cases/common/api'; import { useGetCases, DEFAULT_QUERY_PARAMS, diff --git a/x-pack/plugins/security_solution/public/cases/components/connectors/fields_form.tsx b/x-pack/plugins/security_solution/public/cases/components/connectors/fields_form.tsx index 035f1fa2b63a..841c2a9e38f6 100644 --- a/x-pack/plugins/security_solution/public/cases/components/connectors/fields_form.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/connectors/fields_form.tsx @@ -10,7 +10,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner } from '@elastic/eui'; import { CaseActionConnector, ConnectorFieldsProps } from './types'; import { getCaseConnectors } from '.'; -import { ConnectorTypeFields } from '../../../../../cases/common'; +import { ConnectorTypeFields } from '../../../../../cases/common/api/connectors'; interface Props extends Omit<ConnectorFieldsProps<ConnectorTypeFields['fields']>, 'connector'> { connector: CaseActionConnector | null; diff --git a/x-pack/plugins/security_solution/public/cases/components/connectors/index.ts b/x-pack/plugins/security_solution/public/cases/components/connectors/index.ts index 76f6ccb6a1ad..dad7070aad70 100644 --- a/x-pack/plugins/security_solution/public/cases/components/connectors/index.ts +++ b/x-pack/plugins/security_solution/public/cases/components/connectors/index.ts @@ -15,7 +15,7 @@ import { ServiceNowITSMFieldsType, ServiceNowSIRFieldsType, ResilientFieldsType, -} from '../../../../../cases/common'; +} from '../../../../../cases/common/api/connectors'; export { getActionType as getCaseConnectorUI } from './case'; diff --git a/x-pack/plugins/security_solution/public/cases/components/connectors/jira/case_fields.tsx b/x-pack/plugins/security_solution/public/cases/components/connectors/jira/case_fields.tsx index 985537e79959..22e80d43f34e 100644 --- a/x-pack/plugins/security_solution/public/cases/components/connectors/jira/case_fields.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/connectors/jira/case_fields.tsx @@ -10,7 +10,7 @@ import { map } from 'lodash/fp'; import { EuiFormRow, EuiSelect, EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; import * as i18n from './translations'; -import { ConnectorTypes, JiraFieldsType } from '../../../../../../cases/common'; +import { ConnectorTypes, JiraFieldsType } from '../../../../../../cases/common/api/connectors'; import { useKibana } from '../../../../common/lib/kibana'; import { ConnectorFieldsProps } from '../types'; import { useGetIssueTypes } from './use_get_issue_types'; diff --git a/x-pack/plugins/security_solution/public/cases/components/connectors/jira/index.ts b/x-pack/plugins/security_solution/public/cases/components/connectors/jira/index.ts index 1069e489ada0..40e59a081a44 100644 --- a/x-pack/plugins/security_solution/public/cases/components/connectors/jira/index.ts +++ b/x-pack/plugins/security_solution/public/cases/components/connectors/jira/index.ts @@ -8,7 +8,7 @@ import { lazy } from 'react'; import { CaseConnector } from '../types'; -import { JiraFieldsType } from '../../../../../../cases/common'; +import { JiraFieldsType } from '../../../../../../cases/common/api/connectors'; import * as i18n from './translations'; export * from './types'; diff --git a/x-pack/plugins/security_solution/public/cases/components/connectors/resilient/case_fields.tsx b/x-pack/plugins/security_solution/public/cases/components/connectors/resilient/case_fields.tsx index ae9b5a4dd6f4..b1fbfb1169d0 100644 --- a/x-pack/plugins/security_solution/public/cases/components/connectors/resilient/case_fields.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/connectors/resilient/case_fields.tsx @@ -21,7 +21,7 @@ import { useGetIncidentTypes } from './use_get_incident_types'; import { useGetSeverity } from './use_get_severity'; import * as i18n from './translations'; -import { ConnectorTypes, ResilientFieldsType } from '../../../../../../cases/common'; +import { ConnectorTypes, ResilientFieldsType } from '../../../../../../cases/common/api/connectors'; import { ConnectorCard } from '../card'; const ResilientFieldsComponent: React.FunctionComponent< diff --git a/x-pack/plugins/security_solution/public/cases/components/connectors/resilient/index.ts b/x-pack/plugins/security_solution/public/cases/components/connectors/resilient/index.ts index 21850cdfe4d9..8a2603f39e10 100644 --- a/x-pack/plugins/security_solution/public/cases/components/connectors/resilient/index.ts +++ b/x-pack/plugins/security_solution/public/cases/components/connectors/resilient/index.ts @@ -8,7 +8,7 @@ import { lazy } from 'react'; import { CaseConnector } from '../types'; -import { ResilientFieldsType } from '../../../../../../cases/common'; +import { ResilientFieldsType } from '../../../../../../cases/common/api/connectors'; import * as i18n from './translations'; export * from './types'; diff --git a/x-pack/plugins/security_solution/public/cases/components/connectors/servicenow/index.ts b/x-pack/plugins/security_solution/public/cases/components/connectors/servicenow/index.ts index 02441b2b9f7a..b342095c39ff 100644 --- a/x-pack/plugins/security_solution/public/cases/components/connectors/servicenow/index.ts +++ b/x-pack/plugins/security_solution/public/cases/components/connectors/servicenow/index.ts @@ -8,7 +8,10 @@ import { lazy } from 'react'; import { CaseConnector } from '../types'; -import { ServiceNowITSMFieldsType, ServiceNowSIRFieldsType } from '../../../../../../cases/common'; +import { + ServiceNowITSMFieldsType, + ServiceNowSIRFieldsType, +} from '../../../../../../cases/common/api/connectors'; import * as i18n from './translations'; export const getServiceNowITSMCaseConnector = (): CaseConnector<ServiceNowITSMFieldsType> => { diff --git a/x-pack/plugins/security_solution/public/cases/components/connectors/servicenow/servicenow_itsm_case_fields.tsx b/x-pack/plugins/security_solution/public/cases/components/connectors/servicenow/servicenow_itsm_case_fields.tsx index f705c9005e48..accb8450802d 100644 --- a/x-pack/plugins/security_solution/public/cases/components/connectors/servicenow/servicenow_itsm_case_fields.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/connectors/servicenow/servicenow_itsm_case_fields.tsx @@ -10,7 +10,10 @@ import { EuiFormRow, EuiSelect, EuiSpacer, EuiFlexGroup, EuiFlexItem } from '@el import * as i18n from './translations'; import { ConnectorFieldsProps } from '../types'; -import { ConnectorTypes, ServiceNowITSMFieldsType } from '../../../../../../cases/common'; +import { + ConnectorTypes, + ServiceNowITSMFieldsType, +} from '../../../../../../cases/common/api/connectors'; import { useKibana } from '../../../../common/lib/kibana'; import { ConnectorCard } from '../card'; import { useGetChoices } from './use_get_choices'; diff --git a/x-pack/plugins/security_solution/public/cases/components/connectors/servicenow/servicenow_sir_case_fields.tsx b/x-pack/plugins/security_solution/public/cases/components/connectors/servicenow/servicenow_sir_case_fields.tsx index 2bac7e01a00b..63502e3454fc 100644 --- a/x-pack/plugins/security_solution/public/cases/components/connectors/servicenow/servicenow_sir_case_fields.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/connectors/servicenow/servicenow_sir_case_fields.tsx @@ -8,7 +8,10 @@ import React, { useCallback, useEffect, useMemo, useState, useRef } from 'react'; import { EuiFormRow, EuiSelect, EuiFlexGroup, EuiFlexItem, EuiCheckbox } from '@elastic/eui'; -import { ConnectorTypes, ServiceNowSIRFieldsType } from '../../../../../../cases/common'; +import { + ConnectorTypes, + ServiceNowSIRFieldsType, +} from '../../../../../../cases/common/api/connectors'; import { useKibana } from '../../../../common/lib/kibana'; import { ConnectorFieldsProps } from '../types'; import { ConnectorCard } from '../card'; diff --git a/x-pack/plugins/security_solution/public/cases/components/connectors/types.ts b/x-pack/plugins/security_solution/public/cases/components/connectors/types.ts index 86f0238dd450..11452b966670 100644 --- a/x-pack/plugins/security_solution/public/cases/components/connectors/types.ts +++ b/x-pack/plugins/security_solution/public/cases/components/connectors/types.ts @@ -12,9 +12,9 @@ import { CaseField, ActionConnector, ConnectorTypeFields, -} from '../../../../../cases/common'; +} from '../../../../../cases/common/api'; -export { ThirdPartyField as AllThirdPartyFields } from '../../../../../cases/common'; +export { ThirdPartyField as AllThirdPartyFields } from '../../../../../cases/common/api'; export type CaseActionConnector = ActionConnector; export interface ThirdPartyField { diff --git a/x-pack/plugins/security_solution/public/cases/components/create/connector.tsx b/x-pack/plugins/security_solution/public/cases/components/create/connector.tsx index 516cc5a0d23a..7912d97528cd 100644 --- a/x-pack/plugins/security_solution/public/cases/components/create/connector.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/create/connector.tsx @@ -8,7 +8,7 @@ import React, { memo, useCallback } from 'react'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import { ConnectorTypes } from '../../../../../cases/common'; +import { ConnectorTypes } from '../../../../../cases/common/api'; import { UseField, useFormData, FieldHook, useFormContext } from '../../../shared_imports'; import { useConnectors } from '../../containers/configure/use_connectors'; import { ConnectorSelector } from '../connector_selector/form'; diff --git a/x-pack/plugins/security_solution/public/cases/components/create/form_context.test.tsx b/x-pack/plugins/security_solution/public/cases/components/create/form_context.test.tsx index 9d14acc96c19..99626c4cfb79 100644 --- a/x-pack/plugins/security_solution/public/cases/components/create/form_context.test.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/create/form_context.test.tsx @@ -10,7 +10,7 @@ import { mount, ReactWrapper } from 'enzyme'; import { act, waitFor } from '@testing-library/react'; import { EuiComboBox, EuiComboBoxOptionOption } from '@elastic/eui'; -import { ConnectorTypes } from '../../../../../cases/common'; +import { ConnectorTypes } from '../../../../../cases/common/api'; import { TestProviders } from '../../../common/mock'; import { usePostCase } from '../../containers/use_post_case'; import { useGetTags } from '../../containers/use_get_tags'; diff --git a/x-pack/plugins/security_solution/public/cases/components/create/form_context.tsx b/x-pack/plugins/security_solution/public/cases/components/create/form_context.tsx index 597726e7bb3f..b575dfe42f07 100644 --- a/x-pack/plugins/security_solution/public/cases/components/create/form_context.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/create/form_context.tsx @@ -19,7 +19,7 @@ import { usePostPushToService } from '../../containers/use_post_push_to_service' import { useConnectors } from '../../containers/configure/use_connectors'; import { useCaseConfigure } from '../../containers/configure/use_configure'; import { Case } from '../../containers/types'; -import { CaseType, ConnectorTypes } from '../../../../../cases/common'; +import { CaseType, ConnectorTypes } from '../../../../../cases/common/api'; const initialCaseValue: FormProps = { description: '', diff --git a/x-pack/plugins/security_solution/public/cases/components/create/index.tsx b/x-pack/plugins/security_solution/public/cases/components/create/index.tsx index 484a45248d8c..9f904350b772 100644 --- a/x-pack/plugins/security_solution/public/cases/components/create/index.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/create/index.tsx @@ -18,8 +18,6 @@ import { FormContext } from './form_context'; import { useInsertTimeline } from '../use_insert_timeline'; import { fieldName as descriptionFieldName } from './description'; import { SubmitCaseButton } from './submit_button'; -import { USE_RAC_CASES_UI } from '../../../../common/constants'; -import { useKibana } from '../../../common/lib/kibana'; export const CommonUseField = getUseField({ component: Field }); @@ -41,7 +39,6 @@ const InsertTimeline = () => { }; export const Create = React.memo(() => { - const { cases } = useKibana().services; const history = useHistory(); const onSuccess = useCallback( async ({ id }) => { @@ -56,39 +53,32 @@ export const Create = React.memo(() => { return ( <EuiPanel> - {USE_RAC_CASES_UI ? ( - cases.getCreateCase({ - onCancel: handleSetIsCancel, - onSuccess, - }) - ) : ( - <FormContext onSuccess={onSuccess}> - <CreateCaseForm /> - <Container> - <EuiFlexGroup - alignItems="center" - justifyContent="flexEnd" - gutterSize="xs" - responsive={false} - > - <EuiFlexItem grow={false}> - <EuiButtonEmpty - data-test-subj="create-case-cancel" - size="s" - onClick={handleSetIsCancel} - iconType="cross" - > - {i18n.CANCEL} - </EuiButtonEmpty> - </EuiFlexItem> - <EuiFlexItem grow={false}> - <SubmitCaseButton /> - </EuiFlexItem> - </EuiFlexGroup> - </Container> - <InsertTimeline /> - </FormContext> - )} + <FormContext onSuccess={onSuccess}> + <CreateCaseForm /> + <Container> + <EuiFlexGroup + alignItems="center" + justifyContent="flexEnd" + gutterSize="xs" + responsive={false} + > + <EuiFlexItem grow={false}> + <EuiButtonEmpty + data-test-subj="create-case-cancel" + size="s" + onClick={handleSetIsCancel} + iconType="cross" + > + {i18n.CANCEL} + </EuiButtonEmpty> + </EuiFlexItem> + <EuiFlexItem grow={false}> + <SubmitCaseButton /> + </EuiFlexItem> + </EuiFlexGroup> + </Container> + <InsertTimeline /> + </FormContext> </EuiPanel> ); }); diff --git a/x-pack/plugins/security_solution/public/cases/components/create/mock.ts b/x-pack/plugins/security_solution/public/cases/components/create/mock.ts index a983add030a1..6e17be8d53e5 100644 --- a/x-pack/plugins/security_solution/public/cases/components/create/mock.ts +++ b/x-pack/plugins/security_solution/public/cases/components/create/mock.ts @@ -5,7 +5,8 @@ * 2.0. */ -import { CasePostRequest, CaseType, ConnectorTypes } from '../../../../../cases/common'; +import { CasePostRequest, CaseType } from '../../../../../cases/common/api'; +import { ConnectorTypes } from '../../../../../cases/common/api/connectors'; import { choices } from '../connectors/mock'; export const sampleTags = ['coke', 'pepsi']; diff --git a/x-pack/plugins/security_solution/public/cases/components/create/schema.tsx b/x-pack/plugins/security_solution/public/cases/components/create/schema.tsx index 38321cdbeab5..b069a484d314 100644 --- a/x-pack/plugins/security_solution/public/cases/components/create/schema.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/create/schema.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { CasePostRequest, ConnectorTypeFields } from '../../../../../cases/common'; +import { CasePostRequest, ConnectorTypeFields } from '../../../../../cases/common/api'; import { FIELD_TYPES, fieldValidators, FormSchema } from '../../../shared_imports'; import * as i18n from './translations'; diff --git a/x-pack/plugins/security_solution/public/cases/components/edit_connector/index.tsx b/x-pack/plugins/security_solution/public/cases/components/edit_connector/index.tsx index 0ecb66d54233..f76adfd2a840 100644 --- a/x-pack/plugins/security_solution/public/cases/components/edit_connector/index.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/edit_connector/index.tsx @@ -21,8 +21,9 @@ import styled from 'styled-components'; import { noop } from 'lodash/fp'; import { Form, UseField, useForm } from '../../../shared_imports'; -import { ActionConnector, ConnectorTypeFields } from '../../../../../cases/common'; +import { ConnectorTypeFields } from '../../../../../cases/common/api/connectors'; import { ConnectorSelector } from '../connector_selector/form'; +import { ActionConnector } from '../../../../../cases/common/api'; import { ConnectorFieldsForm } from '../connectors/fields_form'; import { getConnectorById } from '../configure_cases/utils'; import { CaseUserActions } from '../../containers/types'; diff --git a/x-pack/plugins/security_solution/public/cases/components/status/button.test.tsx b/x-pack/plugins/security_solution/public/cases/components/status/button.test.tsx index 3c019369fa08..6bf4eb95bc04 100644 --- a/x-pack/plugins/security_solution/public/cases/components/status/button.test.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/status/button.test.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { mount } from 'enzyme'; -import { CaseStatuses } from '../../../../../cases/common'; +import { CaseStatuses } from '../../../../../cases/common/api'; import { StatusActionButton } from './button'; describe('StatusActionButton', () => { diff --git a/x-pack/plugins/security_solution/public/cases/components/status/button.tsx b/x-pack/plugins/security_solution/public/cases/components/status/button.tsx index 6aa8f540e2e9..5a0d98fc8a11 100644 --- a/x-pack/plugins/security_solution/public/cases/components/status/button.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/status/button.tsx @@ -8,7 +8,7 @@ import React, { memo, useCallback, useMemo } from 'react'; import { EuiButton } from '@elastic/eui'; -import { CaseStatuses, caseStatuses } from '../../../../../cases/common'; +import { CaseStatuses, caseStatuses } from '../../../../../cases/common/api'; import { statuses } from './config'; interface Props { diff --git a/x-pack/plugins/security_solution/public/cases/components/status/config.ts b/x-pack/plugins/security_solution/public/cases/components/status/config.ts index b7bc7dfa3611..47a74549f03c 100644 --- a/x-pack/plugins/security_solution/public/cases/components/status/config.ts +++ b/x-pack/plugins/security_solution/public/cases/components/status/config.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { CaseStatuses } from '../../../../../cases/common'; +import { CaseStatuses } from '../../../../../cases/common/api'; import * as i18n from './translations'; import { AllCaseStatus, Statuses, StatusAll } from './types'; diff --git a/x-pack/plugins/security_solution/public/cases/components/status/stats.test.tsx b/x-pack/plugins/security_solution/public/cases/components/status/stats.test.tsx index 0bf329736144..266ceb04e433 100644 --- a/x-pack/plugins/security_solution/public/cases/components/status/stats.test.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/status/stats.test.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { mount } from 'enzyme'; -import { CaseStatuses } from '../../../../../cases/common'; +import { CaseStatuses } from '../../../../../cases/common/api'; import { Stats } from './stats'; describe('Stats', () => { diff --git a/x-pack/plugins/security_solution/public/cases/components/status/stats.tsx b/x-pack/plugins/security_solution/public/cases/components/status/stats.tsx index 93b8479a55d7..43001c2cf594 100644 --- a/x-pack/plugins/security_solution/public/cases/components/status/stats.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/status/stats.tsx @@ -7,7 +7,7 @@ import React, { memo, useMemo } from 'react'; import { EuiDescriptionList, EuiLoadingSpinner } from '@elastic/eui'; -import { CaseStatuses } from '../../../../../cases/common'; +import { CaseStatuses } from '../../../../../cases/common/api'; import { statuses } from './config'; export interface Props { diff --git a/x-pack/plugins/security_solution/public/cases/components/status/status.test.tsx b/x-pack/plugins/security_solution/public/cases/components/status/status.test.tsx index 05c3b95e163e..eff9d73c2adf 100644 --- a/x-pack/plugins/security_solution/public/cases/components/status/status.test.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/status/status.test.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { mount } from 'enzyme'; -import { CaseStatuses } from '../../../../../cases/common'; +import { CaseStatuses } from '../../../../../cases/common/api'; import { Status } from './status'; describe('Stats', () => { diff --git a/x-pack/plugins/security_solution/public/cases/components/status/types.ts b/x-pack/plugins/security_solution/public/cases/components/status/types.ts index bbe44bce5551..5618e7802579 100644 --- a/x-pack/plugins/security_solution/public/cases/components/status/types.ts +++ b/x-pack/plugins/security_solution/public/cases/components/status/types.ts @@ -6,7 +6,7 @@ */ import { EuiIconType } from '@elastic/eui/src/components/icon/icon'; -import { CaseStatuses } from '../../../../../cases/common'; +import { CaseStatuses } from '../../../../../cases/common/api'; export const StatusAll = 'all' as const; type StatusAllType = typeof StatusAll; diff --git a/x-pack/plugins/security_solution/public/cases/components/timeline_actions/add_to_case_action.tsx b/x-pack/plugins/security_solution/public/cases/components/timeline_actions/add_to_case_action.tsx index ec5a3825ff65..decd37a7646e 100644 --- a/x-pack/plugins/security_solution/public/cases/components/timeline_actions/add_to_case_action.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/timeline_actions/add_to_case_action.tsx @@ -16,7 +16,7 @@ import { EuiToolTip, } from '@elastic/eui'; -import { CommentType, CaseStatuses } from '../../../../../cases/common'; +import { CommentType, CaseStatuses } from '../../../../../cases/common/api'; import { Ecs } from '../../../../common/ecs'; import { ActionIconItem } from '../../../timelines/components/timeline/body/actions/action_icon_item'; import { usePostComment } from '../../containers/use_post_comment'; diff --git a/x-pack/plugins/security_solution/public/cases/components/use_all_cases_modal/all_cases_modal.tsx b/x-pack/plugins/security_solution/public/cases/components/use_all_cases_modal/all_cases_modal.tsx index 54a5dd126396..10ad3d35004b 100644 --- a/x-pack/plugins/security_solution/public/cases/components/use_all_cases_modal/all_cases_modal.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/use_all_cases_modal/all_cases_modal.tsx @@ -10,7 +10,7 @@ import styled from 'styled-components'; import { EuiModal, EuiModalBody, EuiModalHeader, EuiModalHeaderTitle } from '@elastic/eui'; import { useGetUserSavedObjectPermissions } from '../../../common/lib/kibana'; -import { CaseStatuses } from '../../../../../cases/common'; +import { CaseStatuses } from '../../../../../cases/common/api'; import { Case, SubCase } from '../../containers/types'; import { AllCases } from '../all_cases'; import * as i18n from './translations'; diff --git a/x-pack/plugins/security_solution/public/cases/components/use_all_cases_modal/index.tsx b/x-pack/plugins/security_solution/public/cases/components/use_all_cases_modal/index.tsx index 23cc11ef2ef2..0b30f6ac94e0 100644 --- a/x-pack/plugins/security_solution/public/cases/components/use_all_cases_modal/index.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/use_all_cases_modal/index.tsx @@ -6,7 +6,7 @@ */ import React, { useState, useCallback, useMemo } from 'react'; -import { CaseStatuses } from '../../../../../cases/common'; +import { CaseStatuses } from '../../../../../cases/common/api'; import { Case, SubCase } from '../../containers/types'; import { AllCasesModal } from './all_cases_modal'; diff --git a/x-pack/plugins/security_solution/public/cases/components/use_create_case_modal/create_case_modal.tsx b/x-pack/plugins/security_solution/public/cases/components/use_create_case_modal/create_case_modal.tsx index 627dc61c36b0..4b5eb00d95a8 100644 --- a/x-pack/plugins/security_solution/public/cases/components/use_create_case_modal/create_case_modal.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/use_create_case_modal/create_case_modal.tsx @@ -14,7 +14,7 @@ import { CreateCaseForm } from '../create/form'; import { SubmitCaseButton } from '../create/submit_button'; import { Case } from '../../containers/types'; import * as i18n from '../../translations'; -import { CaseType } from '../../../../../cases/common'; +import { CaseType } from '../../../../../cases/common/api'; export interface CreateCaseModalProps { isModalOpen: boolean; diff --git a/x-pack/plugins/security_solution/public/cases/components/use_create_case_modal/index.tsx b/x-pack/plugins/security_solution/public/cases/components/use_create_case_modal/index.tsx index e29ee3f8712d..5d2f54bd1f14 100644 --- a/x-pack/plugins/security_solution/public/cases/components/use_create_case_modal/index.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/use_create_case_modal/index.tsx @@ -6,7 +6,7 @@ */ import React, { useState, useCallback, useMemo } from 'react'; -import { CaseType } from '../../../../../cases/common'; +import { CaseType } from '../../../../../cases/common/api'; import { Case } from '../../containers/types'; import { CreateCaseModal } from './create_case_modal'; diff --git a/x-pack/plugins/security_solution/public/cases/components/use_push_to_service/index.test.tsx b/x-pack/plugins/security_solution/public/cases/components/use_push_to_service/index.test.tsx index 928d0167bbe8..c058473bbfe3 100644 --- a/x-pack/plugins/security_solution/public/cases/components/use_push_to_service/index.test.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/use_push_to_service/index.test.tsx @@ -13,11 +13,12 @@ import '../../../common/mock/match_media'; import { usePushToService, ReturnUsePushToService, UsePushToService } from '.'; import { TestProviders } from '../../../common/mock'; -import { CaseStatuses, ConnectorTypes } from '../../../../../cases/common'; +import { CaseStatuses } from '../../../../../cases/common/api'; import { usePostPushToService } from '../../containers/use_post_push_to_service'; import { basicPush, actionLicenses } from '../../containers/mock'; import { useGetActionLicense } from '../../containers/use_get_action_license'; import { connectorsMock } from '../../containers/configure/mock'; +import { ConnectorTypes } from '../../../../../cases/common/api/connectors'; jest.mock('react-router-dom', () => { const original = jest.requireActual('react-router-dom'); diff --git a/x-pack/plugins/security_solution/public/cases/components/use_push_to_service/index.tsx b/x-pack/plugins/security_solution/public/cases/components/use_push_to_service/index.tsx index 42284cfa7da4..d83ddb08b51d 100644 --- a/x-pack/plugins/security_solution/public/cases/components/use_push_to_service/index.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/use_push_to_service/index.tsx @@ -17,7 +17,7 @@ import { getConfigureCasesUrl, useFormatUrl } from '../../../common/components/l import { CaseCallOut } from '../callout'; import { getLicenseError, getKibanaConfigError } from './helpers'; import * as i18n from './translations'; -import { CaseConnector, ActionConnector, CaseStatuses } from '../../../../../cases/common'; +import { CaseConnector, ActionConnector, CaseStatuses } from '../../../../../cases/common/api'; import { CaseServices } from '../../containers/use_get_case_user_actions'; import { LinkAnchor } from '../../../common/components/links'; import { SecurityPageName } from '../../../app/types'; diff --git a/x-pack/plugins/security_solution/public/cases/components/user_action_tree/helpers.test.tsx b/x-pack/plugins/security_solution/public/cases/components/user_action_tree/helpers.test.tsx index 84408557eb5a..a62c6c0ef682 100644 --- a/x-pack/plugins/security_solution/public/cases/components/user_action_tree/helpers.test.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/user_action_tree/helpers.test.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { mount } from 'enzyme'; -import { CaseStatuses } from '../../../../../cases/common'; +import { CaseStatuses } from '../../../../../cases/common/api'; import { basicPush, getUserAction } from '../../containers/mock'; import { getLabelTitle, getPushedServiceLabelTitle, getConnectorLabelTitle } from './helpers'; import { connectorsMock } from '../../containers/configure/mock'; diff --git a/x-pack/plugins/security_solution/public/cases/components/user_action_tree/helpers.tsx b/x-pack/plugins/security_solution/public/cases/components/user_action_tree/helpers.tsx index a97e2e98cb9a..cc8d560f91b1 100644 --- a/x-pack/plugins/security_solution/public/cases/components/user_action_tree/helpers.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/user_action_tree/helpers.tsx @@ -15,7 +15,7 @@ import { ActionConnector, CaseStatuses, CommentType, -} from '../../../../../cases/common'; +} from '../../../../../cases/common/api'; import { CaseUserActions } from '../../containers/types'; import { CaseServices } from '../../containers/use_get_case_user_actions'; import { parseString } from '../../containers/utils'; diff --git a/x-pack/plugins/security_solution/public/cases/components/user_action_tree/index.tsx b/x-pack/plugins/security_solution/public/cases/components/user_action_tree/index.tsx index d372d62ab16b..f8d6872a4b74 100644 --- a/x-pack/plugins/security_solution/public/cases/components/user_action_tree/index.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/user_action_tree/index.tsx @@ -30,7 +30,7 @@ import { AlertCommentRequestRt, CommentType, ContextTypeUserRt, -} from '../../../../../cases/common'; +} from '../../../../../cases/common/api'; import { CaseServices } from '../../containers/use_get_case_user_actions'; import { parseString } from '../../containers/utils'; import { OnUpdateFields } from '../case_view'; diff --git a/x-pack/plugins/security_solution/public/cases/components/user_action_tree/user_action_alert_comment_event.test.tsx b/x-pack/plugins/security_solution/public/cases/components/user_action_tree/user_action_alert_comment_event.test.tsx index 25080d61a951..3bfdf2d2c5e6 100644 --- a/x-pack/plugins/security_solution/public/cases/components/user_action_tree/user_action_alert_comment_event.test.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/user_action_tree/user_action_alert_comment_event.test.tsx @@ -11,7 +11,7 @@ import { mount } from 'enzyme'; import { TestProviders } from '../../../common/mock'; import { useKibana } from '../../../common/lib/kibana'; import { AlertCommentEvent } from './user_action_alert_comment_event'; -import { CommentType } from '../../../../../cases/common'; +import { CommentType } from '../../../../../cases/common/api'; const props = { alertId: 'alert-id-1', diff --git a/x-pack/plugins/security_solution/public/cases/components/user_action_tree/user_action_alert_comment_event.tsx b/x-pack/plugins/security_solution/public/cases/components/user_action_tree/user_action_alert_comment_event.tsx index a1b6587cfeec..a72bebbaf099 100644 --- a/x-pack/plugins/security_solution/public/cases/components/user_action_tree/user_action_alert_comment_event.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/user_action_tree/user_action_alert_comment_event.tsx @@ -15,7 +15,7 @@ import { getRuleDetailsUrl, useFormatUrl } from '../../../common/components/link import { SecurityPageName } from '../../../app/types'; import * as i18n from './translations'; -import { CommentType } from '../../../../../cases/common'; +import { CommentType } from '../../../../../cases/common/api'; import { LinkAnchor } from '../../../common/components/links'; interface Props { diff --git a/x-pack/plugins/security_solution/public/cases/containers/api.ts b/x-pack/plugins/security_solution/public/cases/containers/api.ts index ca7ab5eb9d7d..644c7dbf716b 100644 --- a/x-pack/plugins/security_solution/public/cases/containers/api.ts +++ b/x-pack/plugins/security_solution/public/cases/containers/api.ts @@ -8,14 +8,9 @@ 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, @@ -23,19 +18,30 @@ import { CaseUserActionsResponse, CommentRequest, CommentType, - getCaseCommentsUrl, - getCaseDetailsUrl, - getCasePushUrl, - getCaseUserActionUrl, - getSubCaseDetailsUrl, - getSubCaseUserActionUrl, - SUB_CASE_DETAILS_URL, - SUB_CASES_PATCH_DEL_URL, SubCasePatchRequest, SubCaseResponse, SubCasesResponse, User, -} from '../../../../cases/common'; +} from '../../../../cases/common/api'; + +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 '../../../../cases/common/constants'; + +import { + getCaseCommentsUrl, + getCasePushUrl, + getCaseDetailsUrl, + getCaseUserActionUrl, + getSubCaseDetailsUrl, + getSubCaseUserActionUrl, +} from '../../../../cases/common/api/helpers'; import { KibanaServices } from '../../common/lib/kibana'; import { StatusAll } from '../components/status'; diff --git a/x-pack/plugins/security_solution/public/cases/containers/configure/api.ts b/x-pack/plugins/security_solution/public/cases/containers/configure/api.ts index c165c493c16d..943724ef0839 100644 --- a/x-pack/plugins/security_solution/public/cases/containers/configure/api.ts +++ b/x-pack/plugins/security_solution/public/cases/containers/configure/api.ts @@ -7,16 +7,20 @@ import { isEmpty } from 'lodash/fp'; import { - ACTION_TYPES_URL, ActionConnector, ActionTypeConnector, + CasesConfigurePatch, + CasesConfigureResponse, + CasesConfigureRequest, +} from '../../../../../cases/common/api'; +import { KibanaServices } from '../../../common/lib/kibana'; + +import { CASE_CONFIGURE_CONNECTORS_URL, CASE_CONFIGURE_URL, - CasesConfigurePatch, - CasesConfigureRequest, - CasesConfigureResponse, -} from '../../../../../cases/common'; -import { KibanaServices } from '../../../common/lib/kibana'; + ACTION_TYPES_URL, +} from '../../../../../cases/common/constants'; + import { ApiProps } from '../types'; import { convertToCamelCase, decodeCaseConfigureResponse } from '../utils'; import { CaseConfigure } from './types'; diff --git a/x-pack/plugins/security_solution/public/cases/containers/configure/use_configure.tsx b/x-pack/plugins/security_solution/public/cases/containers/configure/use_configure.tsx index 2087753b2603..2ec2a73363bf 100644 --- a/x-pack/plugins/security_solution/public/cases/containers/configure/use_configure.tsx +++ b/x-pack/plugins/security_solution/public/cases/containers/configure/use_configure.tsx @@ -15,7 +15,7 @@ import { } from '../../../common/components/toasters'; import * as i18n from './translations'; import { ClosureType, CaseConfigure, CaseConnector, CaseConnectorMapping } from './types'; -import { ConnectorTypes } from '../../../../../cases/common'; +import { ConnectorTypes } from '../../../../../cases/common/api/connectors'; export type ConnectorConfiguration = { connector: CaseConnector } & { closureType: CaseConfigure['closureType']; diff --git a/x-pack/plugins/security_solution/public/cases/containers/types.ts b/x-pack/plugins/security_solution/public/cases/containers/types.ts index d1c17ea56df6..6feb5a1501a7 100644 --- a/x-pack/plugins/security_solution/public/cases/containers/types.ts +++ b/x-pack/plugins/security_solution/public/cases/containers/types.ts @@ -6,20 +6,20 @@ */ import { - AssociationType, - CaseAttributes, - CaseConnector, - CasePatchRequest, - CaseStatuses, - CaseType, - CommentRequest, User, - UserAction, UserActionField, -} from '../../../../cases/common'; + UserAction, + CaseConnector, + CommentRequest, + CaseStatuses, + CaseAttributes, + CasePatchRequest, + CaseType, + AssociationType, +} from '../../../../cases/common/api'; import { CaseStatusWithAllStatus } from '../components/status'; -export { CaseConnector, ActionConnector, CaseStatuses } from '../../../../cases/common'; +export { CaseConnector, ActionConnector, CaseStatuses } from '../../../../cases/common/api'; export type Comment = CommentRequest & { associationType: AssociationType; diff --git a/x-pack/plugins/security_solution/public/cases/containers/use_bulk_update_case.tsx b/x-pack/plugins/security_solution/public/cases/containers/use_bulk_update_case.tsx index ffb964982d30..d39da93a06a4 100644 --- a/x-pack/plugins/security_solution/public/cases/containers/use_bulk_update_case.tsx +++ b/x-pack/plugins/security_solution/public/cases/containers/use_bulk_update_case.tsx @@ -6,7 +6,7 @@ */ import { useCallback, useReducer, useRef, useEffect } from 'react'; -import { CaseStatuses } from '../../../../cases/common'; +import { CaseStatuses } from '../../../../cases/common/api'; import { displaySuccessToast, errorToToaster, diff --git a/x-pack/plugins/security_solution/public/cases/containers/utils.ts b/x-pack/plugins/security_solution/public/cases/containers/utils.ts index e447476d0228..7c33e4481b2a 100644 --- a/x-pack/plugins/security_solution/public/cases/containers/utils.ts +++ b/x-pack/plugins/security_solution/public/cases/containers/utils.ts @@ -13,22 +13,22 @@ import { identity } from 'fp-ts/lib/function'; import { pipe } from 'fp-ts/lib/pipeable'; import { - CaseConfigureResponseRt, - CasePatchRequest, - CaseResponse, - CaseResponseRt, - CasesConfigureResponse, CasesFindResponse, CasesFindResponseRt, + CaseResponse, + CaseResponseRt, CasesResponse, CasesResponseRt, - CasesStatusResponse, CasesStatusResponseRt, + CasesStatusResponse, + throwErrors, + CasesConfigureResponse, + CaseConfigureResponseRt, CaseUserActionsResponse, CaseUserActionsResponseRt, CommentType, - throwErrors, -} from '../../../../cases/common'; + CasePatchRequest, +} from '../../../../cases/common/api'; import { AppToast, ToasterError } from '../../common/components/toasters'; import { AllCases, Case, UpdateByKey } from './types'; import * as i18n from './translations'; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/use_manage_case_action.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/use_manage_case_action.tsx index c19e5c26bdc9..875bc5e64707 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/use_manage_case_action.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/use_manage_case_action.tsx @@ -6,7 +6,7 @@ */ import { useEffect, useRef, useState } from 'react'; -import { ACTION_URL } from '../../../../../../cases/common'; +import { ACTION_URL } from '../../../../../../cases/common/constants'; import { KibanaServices } from '../../../../common/lib/kibana'; interface CaseAction { diff --git a/x-pack/plugins/security_solution/public/index.ts b/x-pack/plugins/security_solution/public/index.ts index 55262fe039b4..f1d1bc3e6280 100644 --- a/x-pack/plugins/security_solution/public/index.ts +++ b/x-pack/plugins/security_solution/public/index.ts @@ -7,8 +7,8 @@ import { PluginInitializerContext } from '../../../../src/core/public'; import { Plugin } from './plugin'; -import { PluginSetup } from './types'; +import { PluginSetup, PluginStart } from './types'; export const plugin = (context: PluginInitializerContext): Plugin => new Plugin(context); -export { Plugin, PluginSetup }; +export { Plugin, PluginSetup, PluginStart }; diff --git a/x-pack/plugins/security_solution/public/timelines/containers/api.ts b/x-pack/plugins/security_solution/public/timelines/containers/api.ts index 4443688fd249..01a85f6309c3 100644 --- a/x-pack/plugins/security_solution/public/timelines/containers/api.ts +++ b/x-pack/plugins/security_solution/public/timelines/containers/api.ts @@ -12,7 +12,7 @@ import { pipe } from 'fp-ts/lib/pipeable'; // eslint-disable-next-line no-restricted-imports import isEmpty from 'lodash/isEmpty'; -import { throwErrors } from '../../../../cases/common'; +import { throwErrors } from '../../../../cases/common/api'; import { TimelineResponse, TimelineResponseType, diff --git a/x-pack/plugins/security_solution/public/types.ts b/x-pack/plugins/security_solution/public/types.ts index e3d2c345a2a6..e88077679e1b 100644 --- a/x-pack/plugins/security_solution/public/types.ts +++ b/x-pack/plugins/security_solution/public/types.ts @@ -22,7 +22,6 @@ import { TriggersAndActionsUIPublicPluginSetup as TriggersActionsSetup, TriggersAndActionsUIPublicPluginStart as TriggersActionsStart, } from '../../triggers_actions_ui/public'; -import { CasesUiStart } from '../../cases/public'; import { SecurityPluginSetup } from '../../security/public'; import { ResolverPluginSetup } from './resolver/types'; import { Inspect } from '../common/search_strategy'; @@ -48,7 +47,6 @@ export interface SetupPlugins { } export interface StartPlugins { - cases: CasesUiStart; data: DataPublicPluginStart; embeddable: EmbeddableStart; inspector: InspectorStart;