[Cases] Align cases lint rules with security solution (#117177)
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
4c5e59db56
commit
d38fb03820
17
.eslintrc.js
17
.eslintrc.js
|
@ -902,17 +902,6 @@ module.exports = {
|
|||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Cases overrides
|
||||
*/
|
||||
{
|
||||
files: ['x-pack/plugins/cases/**/*.{js,mjs,ts,tsx}'],
|
||||
rules: {
|
||||
'no-duplicate-imports': 'off',
|
||||
'@typescript-eslint/no-duplicate-imports': ['error'],
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Security Solution overrides. These rules below are maintained and owned by
|
||||
* the people within the security-solution-platform team. Please see ping them
|
||||
|
@ -928,6 +917,8 @@ module.exports = {
|
|||
'x-pack/plugins/security_solution/common/**/*.{js,mjs,ts,tsx}',
|
||||
'x-pack/plugins/timelines/public/**/*.{js,mjs,ts,tsx}',
|
||||
'x-pack/plugins/timelines/common/**/*.{js,mjs,ts,tsx}',
|
||||
'x-pack/plugins/cases/public/**/*.{js,mjs,ts,tsx}',
|
||||
'x-pack/plugins/cases/common/**/*.{js,mjs,ts,tsx}',
|
||||
],
|
||||
rules: {
|
||||
'import/no-nodejs-modules': 'error',
|
||||
|
@ -949,10 +940,12 @@ module.exports = {
|
|||
files: [
|
||||
'x-pack/plugins/security_solution/**/*.{ts,tsx}',
|
||||
'x-pack/plugins/timelines/**/*.{ts,tsx}',
|
||||
'x-pack/plugins/cases/**/*.{ts,tsx}',
|
||||
],
|
||||
excludedFiles: [
|
||||
'x-pack/plugins/security_solution/**/*.{test,mock,test_helper}.{ts,tsx}',
|
||||
'x-pack/plugins/timelines/**/*.{test,mock,test_helper}.{ts,tsx}',
|
||||
'x-pack/plugins/cases/**/*.{test,mock,test_helper}.{ts,tsx}',
|
||||
],
|
||||
rules: {
|
||||
'@typescript-eslint/no-non-null-assertion': 'error',
|
||||
|
@ -963,6 +956,7 @@ module.exports = {
|
|||
files: [
|
||||
'x-pack/plugins/security_solution/**/*.{ts,tsx}',
|
||||
'x-pack/plugins/timelines/**/*.{ts,tsx}',
|
||||
'x-pack/plugins/cases/**/*.{ts,tsx}',
|
||||
],
|
||||
rules: {
|
||||
'@typescript-eslint/no-this-alias': 'error',
|
||||
|
@ -985,6 +979,7 @@ module.exports = {
|
|||
files: [
|
||||
'x-pack/plugins/security_solution/**/*.{js,mjs,ts,tsx}',
|
||||
'x-pack/plugins/timelines/**/*.{js,mjs,ts,tsx}',
|
||||
'x-pack/plugins/cases/**/*.{js,mjs,ts,tsx}',
|
||||
],
|
||||
plugins: ['eslint-plugin-node', 'react'],
|
||||
env: {
|
||||
|
|
|
@ -60,7 +60,7 @@ export const decodeOrThrow =
|
|||
const getExcessProps = (props: rt.Props, r: Record<string, unknown>): string[] => {
|
||||
const ex: string[] = [];
|
||||
for (const k of Object.keys(r)) {
|
||||
if (!props.hasOwnProperty(k)) {
|
||||
if (!Object.prototype.hasOwnProperty.call(props, k)) {
|
||||
ex.push(k);
|
||||
}
|
||||
}
|
||||
|
@ -89,5 +89,5 @@ export function excess<C extends rt.InterfaceType<rt.Props> | rt.PartialType<rt.
|
|||
codec.encode,
|
||||
codec.props
|
||||
);
|
||||
return r as any;
|
||||
return r as C;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
/* eslint-disable react/display-name */
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { RecursivePartial } from '@elastic/eui/src/components/common';
|
||||
|
|
|
@ -36,7 +36,7 @@ export const mockFormHook = {
|
|||
__readFieldConfigFromSchema: jest.fn(),
|
||||
};
|
||||
|
||||
export const getFormMock = (sampleData: any) => ({
|
||||
export const getFormMock = (sampleData: unknown) => ({
|
||||
...mockFormHook,
|
||||
submit: () =>
|
||||
Promise.resolve({
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { EuiBasicTable as _EuiBasicTable } from '@elastic/eui';
|
||||
import { EuiBasicTable } from '@elastic/eui';
|
||||
import styled from 'styled-components';
|
||||
import { Case, SubCase } from '../../containers/types';
|
||||
import { CasesColumns } from './columns';
|
||||
|
@ -14,7 +14,7 @@ import { AssociationType } from '../../../common';
|
|||
|
||||
type ExpandedRowMap = Record<string, Element> | {};
|
||||
|
||||
const EuiBasicTable: any = _EuiBasicTable;
|
||||
// @ts-expect-error TS2769
|
||||
const BasicTable = styled(EuiBasicTable)`
|
||||
thead {
|
||||
display: none;
|
||||
|
|
|
@ -303,7 +303,10 @@ describe('AllCasesGeneric', () => {
|
|||
|
||||
await waitFor(() => {
|
||||
result.current.map(
|
||||
(i, key) => i.name != null && !i.hasOwnProperty('actions') && checkIt(`${i.name}`, key)
|
||||
(i, key) =>
|
||||
i.name != null &&
|
||||
!Object.prototype.hasOwnProperty.call(i, 'actions') &&
|
||||
checkIt(`${i.name}`, key)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@ -378,7 +381,9 @@ describe('AllCasesGeneric', () => {
|
|||
})
|
||||
);
|
||||
await waitFor(() => {
|
||||
result.current.map((i) => i.name != null && !i.hasOwnProperty('actions'));
|
||||
result.current.map(
|
||||
(i) => i.name != null && !Object.prototype.hasOwnProperty.call(i, 'actions')
|
||||
);
|
||||
expect(wrapper.find(`a[data-test-subj="case-details-link"]`).exists()).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -87,5 +87,8 @@ export const AllCasesSelectorModal: React.FC<AllCasesSelectorModalProps> = React
|
|||
</OwnerProvider>
|
||||
);
|
||||
});
|
||||
|
||||
AllCasesSelectorModal.displayName = 'AllCasesSelectorModal';
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export { AllCasesSelectorModal as default };
|
||||
|
|
|
@ -10,7 +10,7 @@ import {
|
|||
EuiEmptyPrompt,
|
||||
EuiLoadingContent,
|
||||
EuiTableSelectionType,
|
||||
EuiBasicTable as _EuiBasicTable,
|
||||
EuiBasicTable,
|
||||
EuiBasicTableProps,
|
||||
} from '@elastic/eui';
|
||||
import classnames from 'classnames';
|
||||
|
@ -40,12 +40,12 @@ interface CasesTableProps {
|
|||
selection: EuiTableSelectionType<Case>;
|
||||
showActions: boolean;
|
||||
sorting: EuiBasicTableProps<Case>['sorting'];
|
||||
tableRef: MutableRefObject<_EuiBasicTable | undefined>;
|
||||
tableRef: MutableRefObject<EuiBasicTable | undefined>;
|
||||
tableRowProps: EuiBasicTableProps<Case>['rowProps'];
|
||||
userCanCrud: boolean;
|
||||
}
|
||||
|
||||
const EuiBasicTable: any = _EuiBasicTable;
|
||||
// @ts-expect-error TS2769
|
||||
const BasicTable = styled(EuiBasicTable)`
|
||||
${({ theme }) => `
|
||||
.euiTableRow-isExpandedRow.euiTableRow-isSelectable .euiTableCellContent {
|
||||
|
|
|
@ -242,5 +242,7 @@ export const ConfigureCases: React.FC<ConfigureCasesProps> = React.memo((props)
|
|||
);
|
||||
});
|
||||
|
||||
ConfigureCases.displayName = 'ConfigureCases';
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default ConfigureCases;
|
||||
|
|
|
@ -9,8 +9,25 @@ import { i18n } from '@kbn/i18n';
|
|||
import { CaseConnector, CaseConnectorsRegistry } from './types';
|
||||
|
||||
export const createCaseConnectorsRegistry = (): CaseConnectorsRegistry => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const connectors: Map<string, CaseConnector<any>> = new Map();
|
||||
|
||||
function assertConnectorExists(
|
||||
connector: CaseConnector | undefined | null,
|
||||
id: string
|
||||
): asserts connector {
|
||||
if (!connector) {
|
||||
throw new Error(
|
||||
i18n.translate('xpack.cases.connecors.get.missingCaseConnectorErrorMessage', {
|
||||
defaultMessage: 'Object type "{id}" is not registered.',
|
||||
values: {
|
||||
id,
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const registry: CaseConnectorsRegistry = {
|
||||
has: (id: string) => connectors.has(id),
|
||||
register: <UIProps>(connector: CaseConnector<UIProps>) => {
|
||||
|
@ -28,17 +45,9 @@ export const createCaseConnectorsRegistry = (): CaseConnectorsRegistry => {
|
|||
connectors.set(connector.id, connector);
|
||||
},
|
||||
get: <UIProps>(id: string): CaseConnector<UIProps> => {
|
||||
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)!;
|
||||
const connector = connectors.get(id);
|
||||
assertConnectorExists(connector, id);
|
||||
return connector;
|
||||
},
|
||||
list: () => {
|
||||
return Array.from(connectors).map(([id, connector]) => connector);
|
||||
|
|
|
@ -21,7 +21,7 @@ const DescriptionComponent: React.FC<Props> = ({ isLoading }) => {
|
|||
useLensDraftComment();
|
||||
const { setFieldValue } = useFormContext();
|
||||
const [{ title, tags }] = useFormData({ watch: ['title', 'tags'] });
|
||||
const editorRef = useRef<Record<string, any>>();
|
||||
const editorRef = useRef<Record<string, unknown>>();
|
||||
|
||||
useEffect(() => {
|
||||
if (draftComment?.commentId === fieldName && editorRef.current) {
|
||||
|
|
|
@ -98,5 +98,8 @@ export const CreateCase: React.FC<CreateCaseProps> = React.memo((props) => (
|
|||
<CreateCaseComponent {...props} />
|
||||
</OwnerProvider>
|
||||
));
|
||||
|
||||
CreateCase.displayName = 'CreateCase';
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export { CreateCase as default };
|
||||
|
|
|
@ -96,4 +96,6 @@ const MarkdownEditorComponent = forwardRef<MarkdownEditorRef, MarkdownEditorProp
|
|||
}
|
||||
);
|
||||
|
||||
MarkdownEditorComponent.displayName = 'MarkdownEditorComponent';
|
||||
|
||||
export const MarkdownEditor = memo(MarkdownEditorComponent);
|
||||
|
|
|
@ -75,3 +75,5 @@ export const MarkdownEditorForm = React.memo(
|
|||
}
|
||||
)
|
||||
);
|
||||
|
||||
MarkdownEditorForm.displayName = 'MarkdownEditorForm';
|
||||
|
|
|
@ -140,7 +140,7 @@ const LensEditorComponent: LensEuiMarkdownEditorUiPlugin['editor'] = ({
|
|||
});
|
||||
|
||||
lens?.navigateToPrefilledEditor(undefined, {
|
||||
originatingApp: currentAppId!,
|
||||
originatingApp: currentAppId,
|
||||
originatingPath,
|
||||
});
|
||||
}, [
|
||||
|
@ -174,7 +174,7 @@ const LensEditorComponent: LensEuiMarkdownEditorUiPlugin['editor'] = ({
|
|||
}
|
||||
: undefined,
|
||||
{
|
||||
originatingApp: currentAppId!,
|
||||
originatingApp: currentAppId,
|
||||
originatingPath,
|
||||
}
|
||||
);
|
||||
|
@ -310,7 +310,6 @@ const LensEditorComponent: LensEuiMarkdownEditorUiPlugin['editor'] = ({
|
|||
|
||||
if (draftComment) {
|
||||
handleAdd(incomingEmbeddablePackage?.input.attributes, newTimeRange);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}, [embeddable, storage, timefilter, currentAppId, handleAdd, handleUpdate, draftComment]);
|
||||
|
|
|
@ -201,10 +201,10 @@ export class SavedObjectFinderUi extends React.Component<
|
|||
|
||||
public render() {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<>
|
||||
{this.renderSearchBar()}
|
||||
{this.renderListing()}
|
||||
</React.Fragment>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -481,16 +481,23 @@ export class SavedObjectFinderUi extends React.Component<
|
|||
{items.map((item) => {
|
||||
const currentSavedObjectMetaData = savedObjectMetaData.find(
|
||||
(metaData) => metaData.type === item.type
|
||||
)!;
|
||||
);
|
||||
|
||||
if (currentSavedObjectMetaData == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const fullName = currentSavedObjectMetaData.getTooltipForSavedObject
|
||||
? currentSavedObjectMetaData.getTooltipForSavedObject(item.savedObject)
|
||||
: `${item.title} (${currentSavedObjectMetaData!.name})`;
|
||||
: `${item.title} (${currentSavedObjectMetaData.name})`;
|
||||
|
||||
const iconType = (
|
||||
currentSavedObjectMetaData ||
|
||||
({
|
||||
getIconForSavedObject: () => 'document',
|
||||
} as Pick<SavedObjectMetaData<{ title: string }>, 'getIconForSavedObject'>)
|
||||
).getIconForSavedObject(item.savedObject);
|
||||
|
||||
return (
|
||||
<EuiListGroupItem
|
||||
key={item.id}
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
||||
|
||||
import { some } from 'lodash';
|
||||
import useDebounce from 'react-use/lib/useDebounce';
|
||||
import { ContextShape } from '@elastic/eui/src/components/markdown_editor/markdown_context';
|
||||
|
@ -112,6 +114,7 @@ export const useLensButtonToggle = ({
|
|||
) {
|
||||
if (child.type === 'text') break outer; // don't dive into `text` nodes
|
||||
node = child;
|
||||
// eslint-disable-next-line no-continue
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,16 +16,25 @@ interface Props {
|
|||
disableLinks?: boolean;
|
||||
}
|
||||
|
||||
const withDisabledLinks = (disableLinks?: boolean): React.FC<EuiLinkAnchorProps> => {
|
||||
const MarkdownLinkProcessingComponent: React.FC<EuiLinkAnchorProps> = memo((props) => (
|
||||
<MarkdownLink {...props} disableLinks={disableLinks} />
|
||||
));
|
||||
|
||||
MarkdownLinkProcessingComponent.displayName = 'MarkdownLinkProcessingComponent';
|
||||
|
||||
return MarkdownLinkProcessingComponent;
|
||||
};
|
||||
|
||||
const MarkdownRendererComponent: React.FC<Props> = ({ children, disableLinks }) => {
|
||||
const { processingPlugins, parsingPlugins } = usePlugins();
|
||||
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;
|
||||
processingPluginList[1][1].components.a = useMemo(
|
||||
() => withDisabledLinks(disableLinks),
|
||||
[disableLinks]
|
||||
);
|
||||
|
||||
return (
|
||||
<EuiMarkdownFormat
|
||||
|
|
|
@ -100,5 +100,7 @@ export const RecentCases: React.FC<RecentCasesProps> = React.memo((props) => {
|
|||
);
|
||||
});
|
||||
|
||||
RecentCases.displayName = 'RecentCases';
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export { RecentCases as default };
|
||||
|
|
|
@ -396,6 +396,8 @@ const ActionIcon = React.memo<{
|
|||
);
|
||||
});
|
||||
|
||||
ActionIcon.displayName = 'ActionIcon';
|
||||
|
||||
export const getActionAttachment = ({
|
||||
comment,
|
||||
userCanCrud,
|
||||
|
|
|
@ -25,7 +25,7 @@ import * as i18n from './translations';
|
|||
|
||||
import { useUpdateComment } from '../../containers/use_update_comment';
|
||||
import { useCurrentUser } from '../../common/lib/kibana';
|
||||
import { AddComment } from '../add_comment';
|
||||
import { AddComment, AddCommentRefObject } from '../add_comment';
|
||||
import {
|
||||
ActionConnector,
|
||||
ActionsCommentRequestRt,
|
||||
|
@ -52,7 +52,7 @@ import {
|
|||
getActionAttachment,
|
||||
} from './helpers';
|
||||
import { UserActionAvatar } from './user_action_avatar';
|
||||
import { UserActionMarkdown } from './user_action_markdown';
|
||||
import { UserActionMarkdown, UserActionMarkdownRefObject } from './user_action_markdown';
|
||||
import { UserActionTimestamp } from './user_action_timestamp';
|
||||
import { UserActionUsername } from './user_action_username';
|
||||
import { UserActionContentToolbar } from './user_action_content_toolbar';
|
||||
|
@ -131,6 +131,17 @@ const MyEuiCommentList = styled(EuiCommentList)`
|
|||
const DESCRIPTION_ID = 'description';
|
||||
const NEW_ID = 'newComment';
|
||||
|
||||
const isAddCommentRef = (
|
||||
ref: AddCommentRefObject | UserActionMarkdownRefObject | null | undefined
|
||||
): ref is AddCommentRefObject => {
|
||||
const commentRef = ref as AddCommentRefObject;
|
||||
if (commentRef?.addQuote != null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
export const UserActionTree = React.memo(
|
||||
({
|
||||
caseServices,
|
||||
|
@ -167,7 +178,9 @@ export const UserActionTree = React.memo(
|
|||
const { isLoadingIds, patchComment } = useUpdateComment();
|
||||
const currentUser = useCurrentUser();
|
||||
const [manageMarkdownEditIds, setManageMarkdownEditIds] = useState<string[]>([]);
|
||||
const commentRefs = useRef<Record<string, any>>({});
|
||||
const commentRefs = useRef<
|
||||
Record<string, AddCommentRefObject | UserActionMarkdownRefObject | undefined | null>
|
||||
>({});
|
||||
const { clearDraftComment, draftComment, hasIncomingLensState, openLensModal } =
|
||||
useLensDraftComment();
|
||||
|
||||
|
@ -228,8 +241,9 @@ export const UserActionTree = React.memo(
|
|||
|
||||
const handleManageQuote = useCallback(
|
||||
(quote: string) => {
|
||||
if (commentRefs.current[NEW_ID]) {
|
||||
commentRefs.current[NEW_ID].addQuote(quote);
|
||||
const ref = commentRefs?.current[NEW_ID];
|
||||
if (isAddCommentRef(ref)) {
|
||||
ref.addQuote(quote);
|
||||
}
|
||||
|
||||
handleOutlineComment('add-comment');
|
||||
|
@ -337,6 +351,8 @@ export const UserActionTree = React.memo(
|
|||
const userActions: EuiCommentProps[] = useMemo(
|
||||
() =>
|
||||
caseUserActions.reduce<EuiCommentProps[]>(
|
||||
// TODO: Decrease complexity. https://github.com/elastic/kibana/issues/115730
|
||||
// eslint-disable-next-line complexity
|
||||
(comments, action, index) => {
|
||||
// Comment creation
|
||||
if (action.commentId != null && action.action === 'create') {
|
||||
|
@ -664,15 +680,12 @@ export const UserActionTree = React.memo(
|
|||
return prevManageMarkdownEditIds;
|
||||
});
|
||||
|
||||
if (
|
||||
commentRefs.current &&
|
||||
commentRefs.current[draftComment.commentId] &&
|
||||
commentRefs.current[draftComment.commentId].editor?.textarea &&
|
||||
commentRefs.current[draftComment.commentId].editor?.toolbar
|
||||
) {
|
||||
commentRefs.current[draftComment.commentId].setComment(draftComment.comment);
|
||||
const ref = commentRefs?.current?.[draftComment.commentId];
|
||||
|
||||
if (isAddCommentRef(ref) && ref.editor?.textarea) {
|
||||
ref.setComment(draftComment.comment);
|
||||
if (hasIncomingLensState) {
|
||||
openLensModal({ editorRef: commentRefs.current[draftComment.commentId].editor });
|
||||
openLensModal({ editorRef: ref.editor });
|
||||
} else {
|
||||
clearDraftComment();
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ interface UserActionMarkdownProps {
|
|||
onSaveContent: (content: string) => void;
|
||||
}
|
||||
|
||||
interface UserActionMarkdownRefObject {
|
||||
export interface UserActionMarkdownRefObject {
|
||||
setComment: (newComment: string) => void;
|
||||
}
|
||||
|
||||
|
|
|
@ -87,7 +87,7 @@ export const resolveCase = async (
|
|||
signal: AbortSignal
|
||||
): Promise<ResolvedCase> => {
|
||||
const response = await KibanaServices.get().http.fetch<CaseResolveResponse>(
|
||||
getCaseDetailsUrl(caseId) + '/resolve',
|
||||
`${getCaseDetailsUrl(caseId)}/resolve`,
|
||||
{
|
||||
method: 'GET',
|
||||
query: {
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
import { mount } from 'enzyme';
|
||||
|
||||
|
|
|
@ -231,8 +231,10 @@ export class Authorization {
|
|||
? Array.from(featureCaseOwners)
|
||||
: privileges.kibana.reduce<string[]>((authorizedOwners, { authorized, privilege }) => {
|
||||
if (authorized && requiredPrivileges.has(privilege)) {
|
||||
const owner = requiredPrivileges.get(privilege)!;
|
||||
authorizedOwners.push(owner);
|
||||
const owner = requiredPrivileges.get(privilege);
|
||||
if (owner) {
|
||||
authorizedOwners.push(owner);
|
||||
}
|
||||
}
|
||||
|
||||
return authorizedOwners;
|
||||
|
|
|
@ -263,7 +263,7 @@ async function getCombinedCase({
|
|||
id,
|
||||
}),
|
||||
]
|
||||
: [Promise.reject('case connector feature is disabled')]),
|
||||
: [Promise.reject(new Error('case connector feature is disabled'))]),
|
||||
]);
|
||||
|
||||
if (subCasePromise.status === 'fulfilled') {
|
||||
|
|
|
@ -8,10 +8,14 @@
|
|||
import { Boom, isBoom } from '@hapi/boom';
|
||||
import { Logger } from 'src/core/server';
|
||||
|
||||
export interface HTTPError extends Error {
|
||||
statusCode: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class for wrapping errors while preserving the original thrown error.
|
||||
*/
|
||||
class CaseError extends Error {
|
||||
export class CaseError extends Error {
|
||||
public readonly wrappedError?: Error;
|
||||
constructor(message?: string, originalError?: Error) {
|
||||
super(message);
|
||||
|
@ -51,6 +55,13 @@ export function isCaseError(error: unknown): error is CaseError {
|
|||
return error instanceof CaseError;
|
||||
}
|
||||
|
||||
/**
|
||||
* Type guard for determining if an error is an HTTPError
|
||||
*/
|
||||
export function isHTTPError(error: unknown): error is HTTPError {
|
||||
return (error as HTTPError)?.statusCode != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a CaseError that wraps the original thrown error. This also logs the message that will be placed in the CaseError
|
||||
* if the logger was defined.
|
||||
|
|
|
@ -83,6 +83,7 @@ const SwimlaneFieldsSchema = schema.object({
|
|||
|
||||
const NoneFieldsSchema = schema.nullable(schema.object({}));
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const ReducedConnectorFieldsSchema: { [x: string]: any } = {
|
||||
[ConnectorTypes.jira]: JiraFieldsSchema,
|
||||
[ConnectorTypes.resilient]: ResilientFieldsSchema,
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import { CaseResponse } from '../../../common';
|
||||
import { format } from './sir_format';
|
||||
|
||||
describe('ITSM formatter', () => {
|
||||
describe('SIR formatter', () => {
|
||||
const theCase = {
|
||||
id: 'case-id',
|
||||
connector: {
|
||||
|
|
|
@ -45,12 +45,16 @@ export const format: ServiceNowSIRFormat = (theCase, alerts) => {
|
|||
|
||||
if (fieldsToAdd.length > 0) {
|
||||
sirFields = alerts.reduce<Record<SirFieldKey, string[]>>((acc, alert) => {
|
||||
let temp = {};
|
||||
fieldsToAdd.forEach((alertField) => {
|
||||
const field = get(alertFieldMapping[alertField].alertPath, alert);
|
||||
|
||||
if (field && !manageDuplicate[alertFieldMapping[alertField].sirFieldKey].has(field)) {
|
||||
manageDuplicate[alertFieldMapping[alertField].sirFieldKey].add(field);
|
||||
acc = {
|
||||
|
||||
temp = {
|
||||
...acc,
|
||||
...temp,
|
||||
[alertFieldMapping[alertField].sirFieldKey]: [
|
||||
...acc[alertFieldMapping[alertField].sirFieldKey],
|
||||
field,
|
||||
|
@ -58,7 +62,8 @@ export const format: ServiceNowSIRFormat = (theCase, alerts) => {
|
|||
};
|
||||
}
|
||||
});
|
||||
return acc;
|
||||
|
||||
return { ...acc, ...temp };
|
||||
}, sirFields);
|
||||
}
|
||||
|
||||
|
|
|
@ -126,6 +126,11 @@ export class CasePlugin {
|
|||
},
|
||||
featuresPluginStart: plugins.features,
|
||||
actionsPluginStart: plugins.actions,
|
||||
/**
|
||||
* Lens will be always defined as
|
||||
* it is declared as required plugin in kibana.json
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
lensEmbeddableFactory: this.lensEmbeddableFactory!,
|
||||
});
|
||||
|
||||
|
|
|
@ -5,8 +5,9 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { wrapError } from './utils';
|
||||
import { isBoom, boomify } from '@hapi/boom';
|
||||
import { HTTPError } from '../../common';
|
||||
import { wrapError } from './utils';
|
||||
|
||||
describe('Utils', () => {
|
||||
describe('wrapError', () => {
|
||||
|
@ -25,7 +26,7 @@ describe('Utils', () => {
|
|||
});
|
||||
|
||||
it('it set statusCode to errors status code', () => {
|
||||
const error = new Error('Something happened') as any;
|
||||
const error = new Error('Something happened') as HTTPError;
|
||||
error.statusCode = 404;
|
||||
const res = wrapError(error);
|
||||
|
||||
|
|
|
@ -9,18 +9,21 @@ import { Boom, boomify, isBoom } from '@hapi/boom';
|
|||
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import { CustomHttpResponseOptions, ResponseError } from 'kibana/server';
|
||||
import { isCaseError } from '../../common';
|
||||
import { CaseError, isCaseError, HTTPError, isHTTPError } from '../../common';
|
||||
|
||||
/**
|
||||
* Transforms an error into the correct format for a kibana response.
|
||||
*/
|
||||
export function wrapError(error: any): CustomHttpResponseOptions<ResponseError> {
|
||||
|
||||
export function wrapError(
|
||||
error: CaseError | Boom | HTTPError | Error
|
||||
): CustomHttpResponseOptions<ResponseError> {
|
||||
let boom: Boom;
|
||||
|
||||
if (isCaseError(error)) {
|
||||
boom = error.boomify();
|
||||
} else {
|
||||
const options = { statusCode: error.statusCode ?? 500 };
|
||||
const options = { statusCode: isHTTPError(error) ? error.statusCode : 500 };
|
||||
boom = isBoom(error) ? error : boomify(error, options);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,11 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable no-console */
|
||||
/* eslint-disable no-process-exit */
|
||||
|
||||
import yargs from 'yargs';
|
||||
import { ToolingLog } from '@kbn/dev-utils';
|
||||
import { KbnClient } from '@kbn/test';
|
||||
|
|
|
@ -48,8 +48,6 @@ function isEmptyAlert(alert: AlertInfo): boolean {
|
|||
}
|
||||
|
||||
export class AlertService {
|
||||
constructor() {}
|
||||
|
||||
public async updateAlertsStatus({ alerts, scopedClusterClient, logger }: UpdateAlertsStatusArgs) {
|
||||
try {
|
||||
const bucketedAlerts = bucketAlertsByIndexAndStatus(alerts, logger);
|
||||
|
|
Loading…
Reference in a new issue