mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[Synthetics] Configure rules auto for status/tls (#161578)
## Summary
Fixes https://github.com/elastic/kibana/issues/161197
<img width="1906" alt="image"
src="37942f97
-c44e-473a-9753-e6dcd4694d3c">
This commit is contained in:
parent
7035adb4cc
commit
7f8310982d
10 changed files with 277 additions and 87 deletions
|
@ -22,11 +22,21 @@ journey('OverviewScrolling', async ({ page, params }) => {
|
|||
const retry: RetryService = params.getService('retry');
|
||||
|
||||
const listOfRequests: string[] = [];
|
||||
const expected = [
|
||||
'http://localhost:5620/internal/synthetics/service/enablement',
|
||||
'http://localhost:5620/internal/uptime/dynamic_settings',
|
||||
'http://localhost:5620/internal/synthetics/monitor/filters',
|
||||
'http://localhost:5620/internal/uptime/service/locations',
|
||||
'http://localhost:5620/internal/synthetics/overview?sortField=status&sortOrder=asc&',
|
||||
'http://localhost:5620/internal/synthetics/overview_status?&scopeStatusByLocation=true',
|
||||
'http://localhost:5620/internal/synthetics/service/monitors?perPage=10&page=1&sortOrder=asc&sortField=name.keyword&',
|
||||
'http://localhost:5620/internal/synthetics/enable_default_alerting',
|
||||
];
|
||||
|
||||
before(async () => {
|
||||
page.on('request', (request) => {
|
||||
const url = request.url();
|
||||
if (url.includes('/synthetics/') || url.includes('/uptime/')) {
|
||||
if (url.includes('/internal/synthetics/') || url.includes('/internal/uptime/')) {
|
||||
listOfRequests.push(request.url());
|
||||
}
|
||||
});
|
||||
|
@ -67,7 +77,7 @@ journey('OverviewScrolling', async ({ page, params }) => {
|
|||
assertUnique('/service/monitors');
|
||||
assertUnique('/monitor/filters');
|
||||
|
||||
expect(listOfRequests.length).toBe(16);
|
||||
expect(listOfRequests).toEqual(expected);
|
||||
});
|
||||
|
||||
step('scroll until you see showing all monitors', async () => {
|
||||
|
|
|
@ -5,33 +5,51 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { useFetcher } from '@kbn/observability-shared-plugin/public';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { useCallback, useEffect, useMemo } from 'react';
|
||||
import { useKibana } from '@kbn/kibana-react-plugin/public';
|
||||
import { Rule } from '@kbn/triggers-actions-ui-plugin/public';
|
||||
import { useSyntheticsSettingsContext } from '../../../contexts';
|
||||
import {
|
||||
selectSyntheticsAlerts,
|
||||
selectSyntheticsAlertsLoading,
|
||||
} from '../../../state/alert_rules/selectors';
|
||||
import {
|
||||
enableDefaultAlertingSilentlyAction,
|
||||
getDefaultAlertingAction,
|
||||
} from '../../../state/alert_rules';
|
||||
import { SYNTHETICS_TLS_RULE } from '../../../../../../common/constants/synthetics_alerts';
|
||||
import { selectAlertFlyoutVisibility, setAlertFlyoutVisible } from '../../../state';
|
||||
import { enableDefaultAlertingAPI } from '../../../state/alert_rules/api';
|
||||
import { ClientPluginsStart } from '../../../../../plugin';
|
||||
|
||||
export const useSyntheticsAlert = (isOpen: boolean) => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const [defaultRules, setAlert] = useState<{ statusRule: Rule; tlsRule: Rule } | null>(null);
|
||||
const defaultRules = useSelector(selectSyntheticsAlerts);
|
||||
const loading = useSelector(selectSyntheticsAlertsLoading);
|
||||
const alertFlyoutVisible = useSelector(selectAlertFlyoutVisibility);
|
||||
|
||||
const { data, loading } = useFetcher(() => {
|
||||
if (isOpen) {
|
||||
return enableDefaultAlertingAPI();
|
||||
const { canSave } = useSyntheticsSettingsContext();
|
||||
|
||||
const getOrCreateAlerts = useCallback(() => {
|
||||
if (canSave) {
|
||||
dispatch(enableDefaultAlertingSilentlyAction.get());
|
||||
} else {
|
||||
dispatch(getDefaultAlertingAction.get());
|
||||
}
|
||||
}, [isOpen]);
|
||||
}, [canSave, dispatch]);
|
||||
|
||||
useEffect(() => {
|
||||
if (data) {
|
||||
setAlert(data);
|
||||
if (!defaultRules) {
|
||||
// on initial load we prioritize loading the app
|
||||
setTimeout(() => {
|
||||
getOrCreateAlerts();
|
||||
}, 1000);
|
||||
} else {
|
||||
getOrCreateAlerts();
|
||||
}
|
||||
}, [data]);
|
||||
// we don't want to run this on defaultRules change
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [dispatch, isOpen]);
|
||||
|
||||
const { triggersActionsUi } = useKibana<ClientPluginsStart>().services;
|
||||
|
||||
|
|
|
@ -8,8 +8,7 @@
|
|||
import React from 'react';
|
||||
import { waitFor } from '@testing-library/react';
|
||||
import { render } from '../../../utils/testing/rtl_helpers';
|
||||
import { AlertingCallout } from './alerting_callout';
|
||||
import * as alertingHooks from '../../settings/alerting_defaults/hooks/use_alerting_defaults';
|
||||
import { AlertingCallout, MISSING_RULES_PRIVILEGES_LABEL } from './alerting_callout';
|
||||
|
||||
jest.mock('../../../contexts', () => ({
|
||||
...jest.requireActual('../../../contexts'),
|
||||
|
@ -33,23 +32,19 @@ describe('AlertingCallout', () => {
|
|||
[true, false, false],
|
||||
[true, true, false],
|
||||
])('renders correctly', async (hasConnectors, statusAlertEnabled, shouldShowCallout) => {
|
||||
jest.spyOn(alertingHooks, 'useAlertingDefaults').mockReturnValue({
|
||||
settingsLoading: false,
|
||||
connectorsLoading: false,
|
||||
connectors: [],
|
||||
defaultConnectors: hasConnectors ? ['default-connector'] : [],
|
||||
actionTypes: [],
|
||||
options: [
|
||||
{
|
||||
value: 'test',
|
||||
label: 'test',
|
||||
'data-test-subj': 'test',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const { getByText, queryByText } = render(<AlertingCallout />, {
|
||||
state: {
|
||||
dynamicSettings: {
|
||||
...(shouldShowCallout ? { settings: {} } : {}),
|
||||
},
|
||||
defaultAlerting: {
|
||||
data: {
|
||||
statusRule: {},
|
||||
tlsRule: {},
|
||||
},
|
||||
loading: false,
|
||||
success: true,
|
||||
},
|
||||
monitorList: {
|
||||
loaded: true,
|
||||
data: {
|
||||
|
@ -85,23 +80,23 @@ describe('AlertingCallout', () => {
|
|||
])(
|
||||
'overwrites rendering with isAlertingEnabled prop',
|
||||
async (hasConnectors, statusAlertEnabled, shouldShowCallout) => {
|
||||
jest.spyOn(alertingHooks, 'useAlertingDefaults').mockReturnValue({
|
||||
settingsLoading: false,
|
||||
connectorsLoading: false,
|
||||
defaultConnectors: hasConnectors ? ['default-connector'] : [],
|
||||
connectors: [],
|
||||
actionTypes: [],
|
||||
options: [
|
||||
{
|
||||
value: 'test',
|
||||
label: 'test',
|
||||
'data-test-subj': 'test',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const { getByText, queryByText } = render(
|
||||
<AlertingCallout isAlertingEnabled={statusAlertEnabled} />
|
||||
<AlertingCallout isAlertingEnabled={statusAlertEnabled} />,
|
||||
{
|
||||
state: {
|
||||
dynamicSettings: {
|
||||
...(shouldShowCallout ? { settings: {} } : {}),
|
||||
},
|
||||
defaultAlerting: {
|
||||
data: {
|
||||
statusRule: {},
|
||||
tlsRule: {},
|
||||
},
|
||||
loading: false,
|
||||
success: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
|
@ -113,4 +108,21 @@ describe('AlertingCallout', () => {
|
|||
});
|
||||
}
|
||||
);
|
||||
|
||||
it('show call out for missing privileges rules', async () => {
|
||||
const { getByText } = render(<AlertingCallout />, {
|
||||
state: {
|
||||
defaultAlerting: {
|
||||
data: {},
|
||||
loading: false,
|
||||
success: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByText(/Alerts are not being sent/)).toBeInTheDocument();
|
||||
expect(getByText(MISSING_RULES_PRIVILEGES_LABEL)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,22 +5,35 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { EuiButton, EuiCallOut, EuiSpacer } from '@elastic/eui';
|
||||
import { EuiButton, EuiButtonEmpty, EuiCallOut, EuiMarkdownFormat, EuiSpacer } from '@elastic/eui';
|
||||
import { syntheticsSettingsLocatorID } from '@kbn/observability-plugin/common';
|
||||
import { useFetcher } from '@kbn/observability-shared-plugin/public';
|
||||
import { useSessionStorage } from 'react-use';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { isEmpty } from 'lodash';
|
||||
import { selectDynamicSettings } from '../../../state/settings';
|
||||
import {
|
||||
selectSyntheticsAlerts,
|
||||
selectSyntheticsAlertsLoaded,
|
||||
} from '../../../state/alert_rules/selectors';
|
||||
import { selectMonitorListState } from '../../../state';
|
||||
import { getDynamicSettingsAction } from '../../../state/settings/actions';
|
||||
import { useAlertingDefaults } from '../../settings/alerting_defaults/hooks/use_alerting_defaults';
|
||||
import { useSyntheticsStartPlugins } from '../../../contexts';
|
||||
import { useSyntheticsSettingsContext, useSyntheticsStartPlugins } from '../../../contexts';
|
||||
import { ConfigKey } from '../../../../../../common/runtime_types';
|
||||
|
||||
export const AlertingCallout = ({ isAlertingEnabled }: { isAlertingEnabled?: boolean }) => {
|
||||
const dispatch = useDispatch();
|
||||
const [url, setUrl] = useState<string | undefined>('');
|
||||
|
||||
const { defaultConnectors, settingsLoading } = useAlertingDefaults();
|
||||
const defaultRules = useSelector(selectSyntheticsAlerts);
|
||||
const rulesLoaded = useSelector(selectSyntheticsAlertsLoaded);
|
||||
const { settings } = useSelector(selectDynamicSettings);
|
||||
|
||||
const hasDefaultConnector = !settings || !isEmpty(settings?.defaultConnectors);
|
||||
|
||||
const { canSave } = useSyntheticsSettingsContext();
|
||||
|
||||
const {
|
||||
data: { monitors },
|
||||
|
@ -30,45 +43,76 @@ export const AlertingCallout = ({ isAlertingEnabled }: { isAlertingEnabled?: boo
|
|||
const syntheticsLocators = useSyntheticsStartPlugins()?.share?.url.locators;
|
||||
const locator = syntheticsLocators?.get(syntheticsSettingsLocatorID);
|
||||
|
||||
useEffect(() => {
|
||||
async function generateUrl() {
|
||||
const settingsUrl = await locator?.getUrl({});
|
||||
setUrl(settingsUrl);
|
||||
}
|
||||
generateUrl();
|
||||
const { data: url } = useFetcher(() => {
|
||||
return locator?.getUrl({});
|
||||
}, [locator]);
|
||||
|
||||
const hasDefaultConnector =
|
||||
Boolean(defaultConnectors?.length) || (!settingsLoading && Boolean(defaultConnectors?.length));
|
||||
const hasAlertingConfigured =
|
||||
isAlertingEnabled ??
|
||||
(monitorsLoaded &&
|
||||
monitors.some((monitor) => monitor[ConfigKey.ALERT_CONFIG]?.status?.enabled));
|
||||
|
||||
const showCallout = url && !hasDefaultConnector && hasAlertingConfigured;
|
||||
const showCallout = !hasDefaultConnector && hasAlertingConfigured;
|
||||
const hasDefaultRules =
|
||||
!rulesLoaded || Boolean(defaultRules?.statusRule && defaultRules?.tlsRule);
|
||||
const missingRules = !hasDefaultRules && !canSave;
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(getDynamicSettingsAction.get());
|
||||
}, [dispatch]);
|
||||
|
||||
return showCallout ? (
|
||||
return (
|
||||
<>
|
||||
<EuiCallOut
|
||||
title={
|
||||
<FormattedMessage
|
||||
id="xpack.synthetics.alerting.noConnectorsCallout.header"
|
||||
defaultMessage="Alerts are not being sent"
|
||||
/>
|
||||
}
|
||||
color="warning"
|
||||
iconType="warning"
|
||||
>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.synthetics.alerting.noConnectorsCallout.content"
|
||||
defaultMessage="You have monitors with alerting enabled, but there is no default connector configured to send those alerts."
|
||||
/>
|
||||
</p>
|
||||
<MissingRulesCallout
|
||||
url={url}
|
||||
missingConfig={Boolean(showCallout)}
|
||||
missingRules={missingRules}
|
||||
/>
|
||||
<EuiSpacer size="m" />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const MissingRulesCallout = ({
|
||||
url,
|
||||
missingRules,
|
||||
missingConfig,
|
||||
}: {
|
||||
url?: string;
|
||||
missingConfig?: boolean;
|
||||
missingRules?: boolean;
|
||||
}) => {
|
||||
const [isHidden, setIsHidden] = useSessionStorage('MissingRulesCalloutHidden', false);
|
||||
|
||||
if ((!missingConfig && !missingRules) || isHidden) {
|
||||
return null;
|
||||
}
|
||||
const point = missingRules === missingConfig ? '* ' : '';
|
||||
|
||||
const configCallout = missingConfig ? (
|
||||
<EuiMarkdownFormat>{`${point}${MISSING_CONFIG_LABEL}`}</EuiMarkdownFormat>
|
||||
) : null;
|
||||
|
||||
const rulesCallout = missingRules ? (
|
||||
<EuiMarkdownFormat>{`${point}${MISSING_RULES_PRIVILEGES_LABEL}`}</EuiMarkdownFormat>
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<EuiCallOut
|
||||
title={
|
||||
<FormattedMessage
|
||||
id="xpack.synthetics.alerting.noConnectorsCallout.header"
|
||||
defaultMessage="Alerts are not being sent"
|
||||
/>
|
||||
}
|
||||
color="warning"
|
||||
iconType="warning"
|
||||
>
|
||||
<p>
|
||||
{configCallout}
|
||||
{rulesCallout}
|
||||
</p>
|
||||
{missingConfig && (
|
||||
<EuiButton
|
||||
data-test-subj="syntheticsAlertingCalloutLinkButtonButton"
|
||||
href={url}
|
||||
|
@ -79,8 +123,34 @@ export const AlertingCallout = ({ isAlertingEnabled }: { isAlertingEnabled?: boo
|
|||
defaultMessage="Configure now"
|
||||
/>
|
||||
</EuiButton>
|
||||
</EuiCallOut>
|
||||
<EuiSpacer size="m" />
|
||||
</>
|
||||
) : null;
|
||||
)}
|
||||
<EuiButtonEmpty
|
||||
data-test-subj="syntheticsMissingRulesCalloutRemindMeLaterButton"
|
||||
onClick={() => {
|
||||
setIsHidden(true);
|
||||
}}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.synthetics.alerting.remindMeLater.button"
|
||||
defaultMessage="Remind me later"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
</EuiCallOut>
|
||||
);
|
||||
};
|
||||
|
||||
const MISSING_CONFIG_LABEL = i18n.translate(
|
||||
'xpack.synthetics.alerting.noConnectorsCallout.content',
|
||||
{
|
||||
defaultMessage:
|
||||
'You have monitors with alerting enabled, but there is no default connector configured to send those alerts.',
|
||||
}
|
||||
);
|
||||
|
||||
export const MISSING_RULES_PRIVILEGES_LABEL = i18n.translate(
|
||||
'xpack.synthetics.alerting.missingRules.content',
|
||||
{
|
||||
defaultMessage:
|
||||
'You have monitors with alerting enabled, but there is no rules configured to send those alerts. Default rules are automatically created when user with write privileges opens Synthetics app.',
|
||||
}
|
||||
);
|
||||
|
|
|
@ -8,11 +8,21 @@
|
|||
import { Rule } from '@kbn/triggers-actions-ui-plugin/public';
|
||||
import { createAsyncAction } from '../utils/actions';
|
||||
|
||||
export const getDefaultAlertingAction = createAsyncAction<
|
||||
void,
|
||||
{ statusRule: Rule; tlsRule: Rule }
|
||||
>('getDefaultAlertingAction');
|
||||
|
||||
export const enableDefaultAlertingAction = createAsyncAction<
|
||||
void,
|
||||
{ statusRule: Rule; tlsRule: Rule }
|
||||
>('enableDefaultAlertingAction');
|
||||
|
||||
export const enableDefaultAlertingSilentlyAction = createAsyncAction<
|
||||
void,
|
||||
{ statusRule: Rule; tlsRule: Rule }
|
||||
>('enableDefaultAlertingSilentlyAction');
|
||||
|
||||
export const updateDefaultAlertingAction = createAsyncAction<void, Rule>(
|
||||
'updateDefaultAlertingAction'
|
||||
);
|
||||
|
|
|
@ -9,6 +9,10 @@ import { Rule } from '@kbn/triggers-actions-ui-plugin/public';
|
|||
import { SYNTHETICS_API_URLS } from '../../../../../common/constants';
|
||||
import { apiService } from '../../../../utils/api_service';
|
||||
|
||||
export async function getDefaultAlertingAPI(): Promise<{ statusRule: Rule; tlsRule: Rule }> {
|
||||
return apiService.get(SYNTHETICS_API_URLS.ENABLE_DEFAULT_ALERTING);
|
||||
}
|
||||
|
||||
export async function enableDefaultAlertingAPI(): Promise<{ statusRule: Rule; tlsRule: Rule }> {
|
||||
return apiService.post(SYNTHETICS_API_URLS.ENABLE_DEFAULT_ALERTING);
|
||||
}
|
||||
|
|
|
@ -7,9 +7,27 @@
|
|||
|
||||
import { takeLeading } from 'redux-saga/effects';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { enableDefaultAlertingAction, updateDefaultAlertingAction } from './actions';
|
||||
import {
|
||||
enableDefaultAlertingAction,
|
||||
enableDefaultAlertingSilentlyAction,
|
||||
getDefaultAlertingAction,
|
||||
updateDefaultAlertingAction,
|
||||
} from './actions';
|
||||
import { fetchEffectFactory } from '../utils/fetch_effect';
|
||||
import { enableDefaultAlertingAPI, updateDefaultAlertingAPI } from './api';
|
||||
import { enableDefaultAlertingAPI, getDefaultAlertingAPI, updateDefaultAlertingAPI } from './api';
|
||||
|
||||
export function* getDefaultAlertingEffect() {
|
||||
yield takeLeading(
|
||||
getDefaultAlertingAction.get,
|
||||
fetchEffectFactory(
|
||||
getDefaultAlertingAPI,
|
||||
enableDefaultAlertingAction.success,
|
||||
enableDefaultAlertingAction.fail,
|
||||
undefined,
|
||||
failureMessage
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export function* enableDefaultAlertingEffect() {
|
||||
yield takeLeading(
|
||||
|
@ -24,6 +42,19 @@ export function* enableDefaultAlertingEffect() {
|
|||
);
|
||||
}
|
||||
|
||||
export function* enableDefaultAlertingSilentlyEffect() {
|
||||
yield takeLeading(
|
||||
enableDefaultAlertingSilentlyAction.get,
|
||||
fetchEffectFactory(
|
||||
enableDefaultAlertingAPI,
|
||||
enableDefaultAlertingAction.success,
|
||||
enableDefaultAlertingAction.fail,
|
||||
undefined,
|
||||
failureMessage
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export function* updateDefaultAlertingEffect() {
|
||||
yield takeLeading(
|
||||
updateDefaultAlertingAction.get,
|
||||
|
|
|
@ -6,10 +6,17 @@
|
|||
*/
|
||||
|
||||
import { createReducer } from '@reduxjs/toolkit';
|
||||
import { Rule } from '@kbn/triggers-actions-ui-plugin/public';
|
||||
import { IHttpSerializedFetchError } from '..';
|
||||
import { enableDefaultAlertingAction, updateDefaultAlertingAction } from './actions';
|
||||
import {
|
||||
enableDefaultAlertingAction,
|
||||
enableDefaultAlertingSilentlyAction,
|
||||
getDefaultAlertingAction,
|
||||
updateDefaultAlertingAction,
|
||||
} from './actions';
|
||||
|
||||
export interface DefaultAlertingState {
|
||||
data?: { statusRule: Rule; tlsRule: Rule };
|
||||
success: boolean | null;
|
||||
loading: boolean;
|
||||
error: IHttpSerializedFetchError | null;
|
||||
|
@ -23,10 +30,17 @@ const initialSettingState: DefaultAlertingState = {
|
|||
|
||||
export const defaultAlertingReducer = createReducer(initialSettingState, (builder) => {
|
||||
builder
|
||||
.addCase(getDefaultAlertingAction.get, (state) => {
|
||||
state.loading = true;
|
||||
})
|
||||
.addCase(enableDefaultAlertingSilentlyAction.get, (state) => {
|
||||
state.loading = true;
|
||||
})
|
||||
.addCase(enableDefaultAlertingAction.get, (state) => {
|
||||
state.loading = true;
|
||||
})
|
||||
.addCase(enableDefaultAlertingAction.success, (state, action) => {
|
||||
state.data = action.payload;
|
||||
state.success = Boolean(action.payload);
|
||||
state.loading = false;
|
||||
})
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* 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 { createSelector } from 'reselect';
|
||||
import type { SyntheticsAppState } from '../root_reducer';
|
||||
|
||||
const getState = (appState: SyntheticsAppState) => appState.defaultAlerting;
|
||||
export const selectSyntheticsAlerts = createSelector(getState, (state) => state.data);
|
||||
export const selectSyntheticsAlertsLoading = createSelector(getState, (state) => state.loading);
|
||||
export const selectSyntheticsAlertsLoaded = createSelector(getState, (state) => state.success);
|
|
@ -9,7 +9,12 @@ import { all, fork } from 'redux-saga/effects';
|
|||
import { getCertsListEffect } from './certs';
|
||||
import { addGlobalParamEffect, editGlobalParamEffect, getGlobalParamEffect } from './global_params';
|
||||
import { fetchManualTestRunsEffect } from './manual_test_runs/effects';
|
||||
import { enableDefaultAlertingEffect, updateDefaultAlertingEffect } from './alert_rules/effects';
|
||||
import {
|
||||
enableDefaultAlertingEffect,
|
||||
enableDefaultAlertingSilentlyEffect,
|
||||
getDefaultAlertingEffect,
|
||||
updateDefaultAlertingEffect,
|
||||
} from './alert_rules/effects';
|
||||
import { executeEsQueryEffect } from './elasticsearch';
|
||||
import {
|
||||
fetchAlertConnectorsEffect,
|
||||
|
@ -63,5 +68,7 @@ export const rootEffect = function* root(): Generator {
|
|||
fork(editGlobalParamEffect),
|
||||
fork(getGlobalParamEffect),
|
||||
fork(getCertsListEffect),
|
||||
fork(getDefaultAlertingEffect),
|
||||
fork(enableDefaultAlertingSilentlyEffect),
|
||||
]);
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue