Skip to content

Commit

Permalink
[RAM] Add shareable rules list (elastic#132437)
Browse files Browse the repository at this point in the history
* Shareable rules list

* Hide snooze panel in rules list

* Address comments and added tests

* Fix tests

* Fix tests

* Fix lint

* Address design comments and fix tests

Co-authored-by: Kibana Machine <[email protected]>
  • Loading branch information
2 people authored and emilioalvap committed May 23, 2022
1 parent 549574a commit 4845630
Show file tree
Hide file tree
Showing 33 changed files with 2,624 additions and 1,067 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ export const allowedExperimentalValues = Object.freeze({
rulesListDatagrid: true,
internalAlertsTable: false,
internalShareableComponentsSandbox: false,
ruleTagFilter: false,
ruleStatusFilter: false,
ruleTagFilter: true,
ruleStatusFilter: true,
rulesDetailLogs: true,
});

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* 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 { useLoadRuleAggregations } from './use_load_rule_aggregations';
import { RuleStatus } from '../../types';

const MOCK_TAGS = ['a', 'b', 'c'];

const MOCK_AGGS = {
ruleEnabledStatus: { enabled: 2, disabled: 0 },
ruleExecutionStatus: { ok: 1, active: 2, error: 3, pending: 4, unknown: 5, warning: 6 },
ruleMutedStatus: { muted: 0, unmuted: 2 },
ruleTags: MOCK_TAGS,
};

jest.mock('../lib/rule_api', () => ({
loadRuleAggregations: jest.fn(),
}));

const { loadRuleAggregations } = jest.requireMock('../lib/rule_api');

const onError = jest.fn();

describe('useLoadRuleAggregations', () => {
beforeEach(() => {
loadRuleAggregations.mockResolvedValue(MOCK_AGGS);
jest.clearAllMocks();
});

it('should call loadRuleAggregations API and handle result', async () => {
const params = {
searchText: '',
typesFilter: [],
actionTypesFilter: [],
ruleExecutionStatusesFilter: [],
ruleStatusesFilter: [],
tagsFilter: [],
};

const { result, waitForNextUpdate } = renderHook(() =>
useLoadRuleAggregations({
...params,
onError,
})
);

await act(async () => {
result.current.loadRuleAggregations();
await waitForNextUpdate();
});

expect(loadRuleAggregations).toBeCalledWith(expect.objectContaining(params));
expect(result.current.rulesStatusesTotal).toEqual(MOCK_AGGS.ruleExecutionStatus);
});

it('should call loadRuleAggregation API with params and handle result', async () => {
const params = {
searchText: 'test',
typesFilter: ['type1', 'type2'],
actionTypesFilter: ['action1', 'action2'],
ruleExecutionStatusesFilter: ['status1', 'status2'],
ruleStatusesFilter: ['enabled', 'snoozed'] as RuleStatus[],
tagsFilter: ['tag1', 'tag2'],
};

const { result, waitForNextUpdate } = renderHook(() =>
useLoadRuleAggregations({
...params,
onError,
})
);

await act(async () => {
result.current.loadRuleAggregations();
await waitForNextUpdate();
});

expect(loadRuleAggregations).toBeCalledWith(expect.objectContaining(params));
expect(result.current.rulesStatusesTotal).toEqual(MOCK_AGGS.ruleExecutionStatus);
});

it('should call onError if API fails', async () => {
loadRuleAggregations.mockRejectedValue('');
const params = {
searchText: '',
typesFilter: [],
actionTypesFilter: [],
ruleExecutionStatusesFilter: [],
ruleStatusesFilter: [],
tagsFilter: [],
};

const { result } = renderHook(() =>
useLoadRuleAggregations({
...params,
onError,
})
);

await act(async () => {
result.current.loadRuleAggregations();
});

expect(onError).toBeCalled();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* 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 { useState, useCallback, useMemo } from 'react';
import { RuleExecutionStatusValues } from '@kbn/alerting-plugin/common';
import { loadRuleAggregations, LoadRuleAggregationsProps } from '../lib/rule_api';
import { useKibana } from '../../common/lib/kibana';

type UseLoadRuleAggregationsProps = Omit<LoadRuleAggregationsProps, 'http'> & {
onError: (message: string) => void;
};

export function useLoadRuleAggregations({
searchText,
typesFilter,
actionTypesFilter,
ruleExecutionStatusesFilter,
ruleStatusesFilter,
tagsFilter,
onError,
}: UseLoadRuleAggregationsProps) {
const { http } = useKibana().services;

const [rulesStatusesTotal, setRulesStatusesTotal] = useState<Record<string, number>>(
RuleExecutionStatusValues.reduce<Record<string, number>>(
(prev: Record<string, number>, status: string) => ({
...prev,
[status]: 0,
}),
{}
)
);

const internalLoadRuleAggregations = useCallback(async () => {
try {
const rulesAggs = await loadRuleAggregations({
http,
searchText,
typesFilter,
actionTypesFilter,
ruleExecutionStatusesFilter,
ruleStatusesFilter,
tagsFilter,
});
if (rulesAggs?.ruleExecutionStatus) {
setRulesStatusesTotal(rulesAggs.ruleExecutionStatus);
}
} catch (e) {
onError(
i18n.translate(
'xpack.triggersActionsUI.sections.rulesList.unableToLoadRuleStatusInfoMessage',
{
defaultMessage: 'Unable to load rule status info',
}
)
);
}
}, [
http,
searchText,
typesFilter,
actionTypesFilter,
ruleExecutionStatusesFilter,
ruleStatusesFilter,
tagsFilter,
onError,
setRulesStatusesTotal,
]);

return useMemo(
() => ({
loadRuleAggregations: internalLoadRuleAggregations,
rulesStatusesTotal,
setRulesStatusesTotal,
}),
[internalLoadRuleAggregations, rulesStatusesTotal, setRulesStatusesTotal]
);
}
Loading

0 comments on commit 4845630

Please sign in to comment.