Skip to content

Commit

Permalink
[Actionable Observability][BUG] Fix connectors doesn't appear in the …
Browse files Browse the repository at this point in the history
…Rule Details page after creating first connector (elastic#133737) (elastic#138484)

* Move rule actions to the hook which is right call

* Update naming

* Fix when a connector is deleted from connector page  in Stack Management

* Fix tests

* Update tests and mock loadAllActions API

* Remove unused import

* Call the connectors API only when the rule has actions

(cherry picked from commit 44026a5)

Co-authored-by: Faisal Kanout <faisal.kanout@elastic.co>
  • Loading branch information
kibanamachine and fkanout committed Aug 10, 2022
1 parent cfad70b commit 10a06de
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 83 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* 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, useState, useCallback } from 'react';
import { ActionConnector, loadAllActions } from '@kbn/triggers-actions-ui-plugin/public';
import { intersectionBy } from 'lodash';
import { FetchRuleActionConnectorsProps } from '../pages/rule_details/types';
import { ACTIONS_LOAD_ERROR } from '../pages/rule_details/translations';

interface FetchActionConnectors {
isLoadingActionConnectors: boolean;
actionConnectors: Array<ActionConnector<Record<string, unknown>>>;
errorActionConnectors?: string;
}

export function useFetchRuleActionConnectors({
http,
ruleActions,
}: FetchRuleActionConnectorsProps) {
const [actionConnectors, setActionConnector] = useState<FetchActionConnectors>({
isLoadingActionConnectors: true,
actionConnectors: [] as Array<ActionConnector<Record<string, unknown>>>,
errorActionConnectors: undefined,
});

const fetchRuleActionConnectors = useCallback(async () => {
try {
if (!ruleActions || ruleActions.length <= 0) {
setActionConnector((oldState: FetchActionConnectors) => ({
...oldState,
isLoadingActionConnectors: false,
actionConnectors: [],
}));
return;
}
const allActions = await loadAllActions({
http,
});
const actions = intersectionBy(allActions, ruleActions, 'actionTypeId');
setActionConnector((oldState: FetchActionConnectors) => ({
...oldState,
isLoadingActionConnectors: false,
actionConnectors: actions,
}));
} catch (error) {
setActionConnector((oldState: FetchActionConnectors) => ({
...oldState,
isLoadingActionConnectors: false,
errorActionConnectors: ACTIONS_LOAD_ERROR(
error instanceof Error ? error.message : typeof error === 'string' ? error : ''
),
}));
}
}, [http, ruleActions]);
useEffect(() => {
fetchRuleActionConnectors();
}, [fetchRuleActionConnectors]);

return {
...actionConnectors,
reloadRuleActionConnectors: fetchRuleActionConnectors,
};
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
* 2.0.
*/
import React from 'react';
import { ReactWrapper, mount } from 'enzyme';
import { mount } from 'enzyme';
import { nextTick } from '@kbn/test-jest-helpers';
import { act } from 'react-dom/test-utils';
import { Actions } from './actions';
import { observabilityPublicPluginsStartMock } from '../../../observability_public_plugins_start.mock';
import { kibanaStartMock } from '../../../utils/kibana_react.mock';
Expand All @@ -17,14 +19,11 @@ jest.mock('../../../utils/kibana_react', () => ({
useKibana: jest.fn(() => mockUseKibanaReturnValue),
}));

jest.mock('../../../hooks/use_fetch_rule_actions', () => ({
useFetchRuleActions: jest.fn(),
jest.mock('@kbn/triggers-actions-ui-plugin/public/application/lib/action_connector_api', () => ({
loadAllActions: jest.fn(),
}));

const { useFetchRuleActions } = jest.requireMock('../../../hooks/use_fetch_rule_actions');

describe('Actions', () => {
let wrapper: ReactWrapper<any>;
async function setup() {
const ruleActions = [
{
Expand All @@ -38,26 +37,28 @@ describe('Actions', () => {
actionTypeId: '.slack',
},
];
const allActions = [
const { loadAllActions } = jest.requireMock(
'@kbn/triggers-actions-ui-plugin/public/application/lib/action_connector_api'
);
loadAllActions.mockResolvedValueOnce([
{
id: 1,
name: 'Server log',
id: 'a0d2f6c0-e682-11ec-843b-213c67313f8c',
name: 'Email',
config: {},
actionTypeId: '.email',
},
{
id: 'f57cabc0-e660-11ec-8241-7deb55b17f15',
name: 'logs',
config: {},
actionTypeId: '.server-log',
},
{
id: 2,
id: '05b7ab30-e683-11ec-843b-213c67313f8c',
name: 'Slack',
actionTypeId: '.slack',
},
{
id: 3,
name: 'Email',
actionTypeId: '.email',
},
];
useFetchRuleActions.mockReturnValue({
allActions,
});
]);

const actionTypeRegistryMock =
observabilityPublicPluginsStartMock.createStart().triggersActionsUi.actionTypeRegistry;
Expand All @@ -67,13 +68,18 @@ describe('Actions', () => {
{ id: '.email', iconClass: 'email' },
{ id: '.index', iconClass: 'indexOpen' },
]);
wrapper = mount(
const wrapper = mount(
<Actions ruleActions={ruleActions} actionTypeRegistry={actionTypeRegistryMock} />
);
await act(async () => {
await nextTick();
wrapper.update();
});
return wrapper;
}

it("renders action connector icons for user's selected rule actions", async () => {
await setup();
const wrapper = await setup();
wrapper.debug();
expect(wrapper.find('[data-euiicon-type]').length).toBe(2);
expect(wrapper.find('[data-euiicon-type="logsApp"]').length).toBe(1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,29 @@ import {
IconType,
EuiLoadingSpinner,
} from '@elastic/eui';
import { intersectionBy } from 'lodash';
import { suspendedComponentWithProps } from '@kbn/triggers-actions-ui-plugin/public';
import { i18n } from '@kbn/i18n';
import { ActionsProps } from '../types';
import { useFetchRuleActions } from '../../../hooks/use_fetch_rule_actions';
import { useFetchRuleActionConnectors } from '../../../hooks/use_fetch_rule_action_connectors';
import { useKibana } from '../../../utils/kibana_react';

export function Actions({ ruleActions, actionTypeRegistry }: ActionsProps) {
const {
http,
notifications: { toasts },
} = useKibana().services;
const { isLoadingActions, allActions, errorActions } = useFetchRuleActions({ http });
const { isLoadingActionConnectors, actionConnectors, errorActionConnectors } =
useFetchRuleActionConnectors({
http,
ruleActions,
});
useEffect(() => {
if (errorActions) {
toasts.addDanger({ title: errorActions });
if (errorActionConnectors) {
toasts.addDanger({ title: errorActionConnectors });
}
}, [errorActions, toasts]);
if (ruleActions && ruleActions.length <= 0)
}, [errorActionConnectors, toasts]);

if (!actionConnectors || actionConnectors.length <= 0)
return (
<EuiFlexItem>
<EuiText size="s">
Expand All @@ -49,11 +53,10 @@ export function Actions({ ruleActions, actionTypeRegistry }: ActionsProps) {
? actionGroup?.iconClass
: suspendedComponentWithProps(actionGroup?.iconClass as React.ComponentType);
}
const actions = intersectionBy(allActions, ruleActions, 'actionTypeId');
if (isLoadingActions) return <EuiLoadingSpinner size="s" />;
if (isLoadingActionConnectors) return <EuiLoadingSpinner size="s" />;
return (
<EuiFlexGroup direction="column">
{actions.map(({ actionTypeId, name }) => (
{actionConnectors.map(({ actionTypeId, name }) => (
<React.Fragment key={actionTypeId}>
<EuiFlexGroup alignItems="center" gutterSize="s" component="span">
<EuiFlexItem grow={false}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,9 @@ export interface FetchRuleSummaryProps {
ruleId: string;
http: HttpSetup;
}
export interface FetchRuleActionsProps {
export interface FetchRuleActionConnectorsProps {
http: HttpSetup;
ruleActions: any[];
}

export interface FetchRuleExecutionLogProps {
Expand Down

0 comments on commit 10a06de

Please sign in to comment.