mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[Actionable Observability] consume tags filter (#131220)
* consume tags filter * add getRuleTagFilter to the observability start mock * use loadRuleTags instead of loadRuleAggregations * add an error when rule tag fail to load * load tags errors in a useEffect * fix failing unit tests * load rule errors in a useEffect * stop loading loadRuleTagsAggs twice Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
e474e9460d
commit
1cc8c38a98
7 changed files with 84 additions and 20 deletions
|
@ -7,9 +7,9 @@
|
|||
|
||||
import { useEffect, useState, useCallback } from 'react';
|
||||
import { isEmpty } from 'lodash';
|
||||
import { loadRules } from '@kbn/triggers-actions-ui-plugin/public';
|
||||
import { RULES_LOAD_ERROR } from '../pages/rules/translations';
|
||||
import { FetchRulesProps, RuleState } from '../pages/rules/types';
|
||||
import { loadRules, loadRuleTags } from '@kbn/triggers-actions-ui-plugin/public';
|
||||
import { RULES_LOAD_ERROR, RULE_TAGS_LOAD_ERROR } from '../pages/rules/translations';
|
||||
import { FetchRulesProps, RuleState, TagsState } from '../pages/rules/types';
|
||||
import { OBSERVABILITY_RULE_TYPES } from '../pages/rules/config';
|
||||
import { useKibana } from '../utils/kibana_react';
|
||||
|
||||
|
@ -18,6 +18,7 @@ export function useFetchRules({
|
|||
ruleLastResponseFilter,
|
||||
ruleStatusesFilter,
|
||||
typesFilter,
|
||||
tagsFilter,
|
||||
setPage,
|
||||
page,
|
||||
sort,
|
||||
|
@ -33,6 +34,23 @@ export function useFetchRules({
|
|||
|
||||
const [noData, setNoData] = useState<boolean>(true);
|
||||
const [initialLoad, setInitialLoad] = useState<boolean>(true);
|
||||
const [tagsState, setTagsState] = useState<TagsState>({
|
||||
data: [],
|
||||
error: null,
|
||||
});
|
||||
const loadRuleTagsAggs = useCallback(async () => {
|
||||
try {
|
||||
const ruleTagsAggs = await loadRuleTags({
|
||||
http,
|
||||
});
|
||||
|
||||
if (ruleTagsAggs?.ruleTags) {
|
||||
setTagsState({ data: ruleTagsAggs.ruleTags, error: null });
|
||||
}
|
||||
} catch (e) {
|
||||
setTagsState((oldState: TagsState) => ({ ...oldState, error: RULE_TAGS_LOAD_ERROR }));
|
||||
}
|
||||
}, [http]);
|
||||
|
||||
const fetchRules = useCallback(async () => {
|
||||
setRulesState((oldState) => ({ ...oldState, isLoading: true }));
|
||||
|
@ -43,10 +61,12 @@ export function useFetchRules({
|
|||
page,
|
||||
searchText,
|
||||
typesFilter: typesFilter.length > 0 ? typesFilter : OBSERVABILITY_RULE_TYPES,
|
||||
tagsFilter,
|
||||
ruleExecutionStatusesFilter: ruleLastResponseFilter,
|
||||
ruleStatusesFilter,
|
||||
sort,
|
||||
});
|
||||
await loadRuleTagsAggs();
|
||||
setRulesState((oldState) => ({
|
||||
...oldState,
|
||||
isLoading: false,
|
||||
|
@ -60,8 +80,9 @@ export function useFetchRules({
|
|||
const isFilterApplied = !(
|
||||
isEmpty(searchText) &&
|
||||
isEmpty(ruleLastResponseFilter) &&
|
||||
isEmpty(ruleStatusesFilter) &&
|
||||
isEmpty(typesFilter)
|
||||
isEmpty(typesFilter) &&
|
||||
isEmpty(tagsFilter) &&
|
||||
isEmpty(ruleStatusesFilter)
|
||||
);
|
||||
|
||||
setNoData(response.data.length === 0 && !isFilterApplied);
|
||||
|
@ -75,6 +96,8 @@ export function useFetchRules({
|
|||
setPage,
|
||||
searchText,
|
||||
ruleLastResponseFilter,
|
||||
tagsFilter,
|
||||
loadRuleTagsAggs,
|
||||
ruleStatusesFilter,
|
||||
typesFilter,
|
||||
sort,
|
||||
|
@ -89,5 +112,6 @@ export function useFetchRules({
|
|||
setRulesState,
|
||||
noData,
|
||||
initialLoad,
|
||||
tagsState,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ const triggersActionsUiStartMock = {
|
|||
getRuleStatusDropdown: jest.fn(),
|
||||
getRuleTagBadge: jest.fn(),
|
||||
getRuleStatusFilter: jest.fn(),
|
||||
getRuleTagFilter: jest.fn(),
|
||||
ruleTypeRegistry: {
|
||||
has: jest.fn(),
|
||||
register: jest.fn(),
|
||||
|
|
|
@ -86,7 +86,11 @@ describe('empty RulesPage', () => {
|
|||
},
|
||||
],
|
||||
});
|
||||
useFetchRules.mockReturnValue({ rulesState, noData: true });
|
||||
useFetchRules.mockReturnValue({
|
||||
rulesState,
|
||||
noData: true,
|
||||
tagsState: { data: [], error: null },
|
||||
});
|
||||
wrapper = mountWithIntl(<RulesPage />);
|
||||
}
|
||||
it('renders empty screen', async () => {
|
||||
|
@ -138,7 +142,11 @@ describe('empty RulesPage with show only capability', () => {
|
|||
ruleTaskTimeout: '1m',
|
||||
},
|
||||
];
|
||||
useFetchRules.mockReturnValue({ rulesState, noData: true });
|
||||
useFetchRules.mockReturnValue({
|
||||
rulesState,
|
||||
noData: true,
|
||||
tagsState: { data: [], error: null },
|
||||
});
|
||||
useLoadRuleTypes.mockReturnValue({ ruleTypes });
|
||||
|
||||
wrapper = mountWithIntl(<RulesPage />);
|
||||
|
@ -352,7 +360,7 @@ describe('RulesPage with items', () => {
|
|||
ruleTypes,
|
||||
ruleTypeIndex: mockedRuleTypeIndex,
|
||||
});
|
||||
useFetchRules.mockReturnValue({ rulesState });
|
||||
useFetchRules.mockReturnValue({ rulesState, tagsState: { data: [], error: null } });
|
||||
wrapper = mountWithIntl(<RulesPage />);
|
||||
await act(async () => {
|
||||
await nextTick();
|
||||
|
@ -509,7 +517,7 @@ describe('RulesPage with items and show only capability', () => {
|
|||
error: null,
|
||||
totalItemCount: 3,
|
||||
};
|
||||
useFetchRules.mockReturnValue({ rulesState });
|
||||
useFetchRules.mockReturnValue({ rulesState, tagsState: { data: [], error: null } });
|
||||
|
||||
const mockedRuleTypeIndex = new Map(
|
||||
Object.entries({
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { useState, useMemo, useCallback } from 'react';
|
||||
import React, { useState, useMemo, useCallback, useEffect } from 'react';
|
||||
import { capitalize, sortBy } from 'lodash';
|
||||
import {
|
||||
EuiButton,
|
||||
|
@ -93,6 +93,7 @@ function RulesPage() {
|
|||
});
|
||||
const [inputText, setInputText] = useState<string | undefined>();
|
||||
const [searchText, setSearchText] = useState<string | undefined>();
|
||||
const [tagsFilter, setTagsFilter] = useState<string[]>([]);
|
||||
const [typesFilter, setTypesFilter] = useState<string[]>([]);
|
||||
const { lastResponse, setLastResponse } = useRulesPageStateContainer();
|
||||
const { status, setStatus } = useRulesPageStateContainer();
|
||||
|
@ -108,16 +109,19 @@ function RulesPage() {
|
|||
setCurrentRuleToEdit(ruleItem);
|
||||
};
|
||||
|
||||
const { rulesState, setRulesState, reload, noData, initialLoad } = useFetchRules({
|
||||
const { rulesState, setRulesState, reload, noData, initialLoad, tagsState } = useFetchRules({
|
||||
searchText,
|
||||
ruleLastResponseFilter: lastResponse,
|
||||
ruleStatusesFilter: status,
|
||||
typesFilter,
|
||||
tagsFilter,
|
||||
page,
|
||||
setPage,
|
||||
sort,
|
||||
});
|
||||
const { data: rules, totalItemCount, error } = rulesState;
|
||||
const { data: tags, error: tagsError } = tagsState;
|
||||
|
||||
const { ruleTypeIndex, ruleTypes } = useLoadRuleTypes({
|
||||
filteredSolutions: OBSERVABILITY_SOLUTIONS,
|
||||
});
|
||||
|
@ -165,6 +169,18 @@ function RulesPage() {
|
|||
},
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (tagsError) {
|
||||
toasts.addDanger({
|
||||
title: tagsError,
|
||||
});
|
||||
}
|
||||
if (error)
|
||||
toasts.addDanger({
|
||||
title: error,
|
||||
});
|
||||
}, [tagsError, error, toasts]);
|
||||
|
||||
const getRulesTableColumns = () => {
|
||||
return [
|
||||
{
|
||||
|
@ -182,11 +198,11 @@ function RulesPage() {
|
|||
sortable: false,
|
||||
width: '50px',
|
||||
'data-test-subj': 'rulesTableCell-tagsPopover',
|
||||
render: (tags: string[], item: RuleTableItem) => {
|
||||
return tags.length > 0
|
||||
render: (ruleTags: string[], item: RuleTableItem) => {
|
||||
return ruleTags.length > 0
|
||||
? triggersActionsUi.getRuleTagBadge({
|
||||
isOpen: tagPopoverOpenIndex === item.index,
|
||||
tags,
|
||||
tags: ruleTags,
|
||||
onClick: () => setTagPopoverOpenIndex(item.index),
|
||||
onClose: () => setTagPopoverOpenIndex(-1),
|
||||
})
|
||||
|
@ -352,6 +368,13 @@ function RulesPage() {
|
|||
)}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
{triggersActionsUi.getRuleTagFilter({
|
||||
tags,
|
||||
selectedTags: tagsFilter,
|
||||
onChange: (myTags: string[]) => setTagsFilter(myTags),
|
||||
})}
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<LastResponseFilter
|
||||
key="rule-lastResponse-filter"
|
||||
|
@ -415,7 +438,6 @@ function RulesPage() {
|
|||
</>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<ObservabilityPageTemplate
|
||||
pageHeader={{
|
||||
|
@ -478,10 +500,6 @@ function RulesPage() {
|
|||
/>
|
||||
|
||||
{getRulesTable()}
|
||||
{error &&
|
||||
toasts.addDanger({
|
||||
title: error,
|
||||
})}
|
||||
{currentRuleToEdit && <EditRuleFlyout onSave={reload} currentRule={currentRuleToEdit} />}
|
||||
{createRuleFlyoutVisibility && CreateRuleFlyout}
|
||||
</ObservabilityPageTemplate>
|
||||
|
|
|
@ -125,6 +125,13 @@ export const RULES_LOAD_ERROR = i18n.translate('xpack.observability.rules.loadEr
|
|||
defaultMessage: 'Unable to load rules',
|
||||
});
|
||||
|
||||
export const RULE_TAGS_LOAD_ERROR = i18n.translate(
|
||||
'xpack.observability.rulesList.unableToLoadRuleTags',
|
||||
{
|
||||
defaultMessage: 'Unable to load rule tags',
|
||||
}
|
||||
);
|
||||
|
||||
export const RULES_SINGLE_TITLE = i18n.translate(
|
||||
'xpack.observability.rules.rulesTable.singleTitle',
|
||||
{
|
||||
|
|
|
@ -44,6 +44,7 @@ export interface FetchRulesProps {
|
|||
ruleLastResponseFilter: string[];
|
||||
ruleStatusesFilter: RuleStatus[];
|
||||
typesFilter: string[];
|
||||
tagsFilter: string[];
|
||||
page: Pagination;
|
||||
setPage: Dispatch<SetStateAction<Pagination>>;
|
||||
sort: EuiTableSortingType<RuleTableItem>['sort'];
|
||||
|
@ -66,3 +67,8 @@ export interface RuleState {
|
|||
error: string | null;
|
||||
totalItemCount: number;
|
||||
}
|
||||
|
||||
export interface TagsState {
|
||||
data: string[];
|
||||
error: string | null;
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ export { muteRule } from './application/lib/rule_api/mute';
|
|||
export { unmuteRule } from './application/lib/rule_api/unmute';
|
||||
export { snoozeRule } from './application/lib/rule_api/snooze';
|
||||
export { unsnoozeRule } from './application/lib/rule_api/unsnooze';
|
||||
export { loadRuleAggregations } from './application/lib/rule_api/aggregate';
|
||||
export { loadRuleAggregations, loadRuleTags } from './application/lib/rule_api/aggregate';
|
||||
export { useLoadRuleTypes } from './application/hooks/use_load_rule_types';
|
||||
|
||||
export { loadActionTypes } from './application/lib/action_connector_api/connector_types';
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue