mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[Uptime] monitor management - adjust deletion logic (#146908)
## Summary Resolves https://github.com/elastic/kibana/issues/146932 Adjusts monitor delete logic for Uptime to ensure that multiple monitors are able to be deleted in a row. ### Testing 1. Create at least two monitors 2. Navigate to Uptime monitor management. Delete a monitor. Ensure the success toast appears and the monitor is removed from the monitor list 3. Delete a second monitor. Ensure the success toast appears and the monitor is removed from the list. Co-authored-by: shahzad31 <shahzad31comp@gmail.com>
This commit is contained in:
parent
b12859fed9
commit
7e9f57ccce
18 changed files with 229 additions and 141 deletions
|
@ -75,6 +75,7 @@ export const Actions = ({
|
|||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<DeleteMonitor
|
||||
key={configId}
|
||||
onUpdate={onUpdate}
|
||||
name={name}
|
||||
configId={configId}
|
||||
|
|
|
@ -6,11 +6,9 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { screen, fireEvent } from '@testing-library/react';
|
||||
import { screen, fireEvent, waitFor } from '@testing-library/react';
|
||||
import { render } from '../../../lib/helper/rtl_helpers';
|
||||
import * as fetchers from '../../../state/api/monitor_management';
|
||||
import { FETCH_STATUS, useFetcher as originalUseFetcher } from '@kbn/observability-plugin/public';
|
||||
import { spyOnUseFetcher } from '../../../lib/helper/spy_use_fetcher';
|
||||
import { Actions } from './actions';
|
||||
import { DeleteMonitor } from './delete_monitor';
|
||||
import {
|
||||
|
@ -19,17 +17,21 @@ import {
|
|||
MonitorManagementListResult,
|
||||
SourceType,
|
||||
} from '../../../../../common/runtime_types';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
import { createRealStore } from '../../../lib/helper/helper_with_redux';
|
||||
|
||||
describe('<DeleteMonitor />', () => {
|
||||
const onUpdate = jest.fn();
|
||||
const useFetcher = spyOnUseFetcher({});
|
||||
|
||||
it('calls delete monitor on monitor deletion', () => {
|
||||
useFetcher.mockImplementation(originalUseFetcher);
|
||||
it('calls delete monitor on monitor deletion', async () => {
|
||||
const deleteMonitor = jest.spyOn(fetchers, 'deleteMonitor');
|
||||
const id = 'test-id';
|
||||
render(<DeleteMonitor configId={id} name="sample name" onUpdate={onUpdate} />);
|
||||
const store = createRealStore();
|
||||
render(<DeleteMonitor configId={id} name="sample name" onUpdate={onUpdate} />, {
|
||||
store,
|
||||
});
|
||||
|
||||
const dispatchSpy = jest.spyOn(store, 'dispatch');
|
||||
|
||||
expect(deleteMonitor).not.toBeCalled();
|
||||
|
||||
|
@ -37,12 +39,24 @@ describe('<DeleteMonitor />', () => {
|
|||
|
||||
fireEvent.click(screen.getByTestId('confirmModalConfirmButton'));
|
||||
|
||||
expect(deleteMonitor).toBeCalledWith({ id });
|
||||
expect(dispatchSpy).toHaveBeenCalledWith({
|
||||
payload: {
|
||||
id: 'test-id',
|
||||
name: 'sample name',
|
||||
},
|
||||
type: 'DELETE_MONITOR',
|
||||
});
|
||||
|
||||
expect(store.getState().deleteMonitor.loading.includes(id)).toEqual(true);
|
||||
|
||||
expect(await screen.findByLabelText('Loading')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('calls set refresh when deletion is successful', () => {
|
||||
it('calls set refresh when deletion is successful', async () => {
|
||||
const id = 'test-id';
|
||||
const name = 'sample monitor';
|
||||
const store = createRealStore();
|
||||
|
||||
render(
|
||||
<Actions
|
||||
configId={id}
|
||||
|
@ -59,40 +73,18 @@ describe('<DeleteMonitor />', () => {
|
|||
},
|
||||
] as unknown as MonitorManagementListResult['monitors']
|
||||
}
|
||||
/>
|
||||
/>,
|
||||
{ store }
|
||||
);
|
||||
|
||||
userEvent.click(screen.getByTestId('monitorManagementDeleteMonitor'));
|
||||
fireEvent.click(screen.getByRole('button'));
|
||||
|
||||
expect(onUpdate).toHaveBeenCalled();
|
||||
});
|
||||
fireEvent.click(screen.getByTestId('confirmModalConfirmButton'));
|
||||
|
||||
it('shows loading spinner while waiting for monitor to delete', () => {
|
||||
const id = 'test-id';
|
||||
useFetcher.mockReturnValue({
|
||||
data: {},
|
||||
status: FETCH_STATUS.LOADING,
|
||||
refetch: () => {},
|
||||
await waitFor(() => {
|
||||
expect(onUpdate).toHaveBeenCalled();
|
||||
});
|
||||
render(
|
||||
<Actions
|
||||
configId={id}
|
||||
name="sample name"
|
||||
onUpdate={onUpdate}
|
||||
monitors={
|
||||
[
|
||||
{
|
||||
id,
|
||||
attributes: {
|
||||
[ConfigKey.MONITOR_SOURCE_TYPE]: SourceType.PROJECT,
|
||||
[ConfigKey.CONFIG_ID]: id,
|
||||
} as BrowserFields,
|
||||
},
|
||||
] as unknown as MonitorManagementListResult['monitors']
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(screen.getByLabelText('Deleting monitor...')).toBeInTheDocument();
|
||||
expect(store.getState().deleteMonitor.deletedMonitorIds.includes(id)).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -7,22 +7,19 @@
|
|||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import {
|
||||
EuiButtonIcon,
|
||||
EuiCallOut,
|
||||
EuiConfirmModal,
|
||||
EuiLoadingSpinner,
|
||||
EuiSpacer,
|
||||
} from '@elastic/eui';
|
||||
import { EuiButtonIcon, EuiCallOut, EuiConfirmModal, EuiSpacer } from '@elastic/eui';
|
||||
|
||||
import { FETCH_STATUS, useFetcher } from '@kbn/observability-plugin/public';
|
||||
import { toMountPoint } from '@kbn/kibana-react-plugin/public';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { deleteMonitorAction } from '../../../state/actions/delete_monitor';
|
||||
import { AppState } from '../../../state';
|
||||
import {
|
||||
ProjectMonitorDisclaimer,
|
||||
PROJECT_MONITOR_TITLE,
|
||||
} from '../../../../apps/synthetics/components/monitors_page/management/monitor_list_table/delete_monitor';
|
||||
import { deleteMonitor } from '../../../state/api';
|
||||
import { kibanaService } from '../../../state/kibana_service';
|
||||
import {
|
||||
deleteMonitorLoadingSelector,
|
||||
deleteMonitorSuccessSelector,
|
||||
} from '../../../state/selectors';
|
||||
|
||||
export const DeleteMonitor = ({
|
||||
configId,
|
||||
|
@ -37,61 +34,34 @@ export const DeleteMonitor = ({
|
|||
isProjectMonitor?: boolean;
|
||||
onUpdate: () => void;
|
||||
}) => {
|
||||
const [isDeleting, setIsDeleting] = useState<boolean>(false);
|
||||
const [isDeleteModalVisible, setIsDeleteModalVisible] = useState(false);
|
||||
|
||||
const isDeleting = useSelector((state: AppState) =>
|
||||
deleteMonitorLoadingSelector(state, configId)
|
||||
);
|
||||
|
||||
const isSuccessfullyDeleted = useSelector((state: AppState) =>
|
||||
deleteMonitorSuccessSelector(state, configId)
|
||||
);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const onConfirmDelete = () => {
|
||||
setIsDeleting(true);
|
||||
dispatch(deleteMonitorAction.get({ id: configId, name }));
|
||||
setIsDeleteModalVisible(false);
|
||||
};
|
||||
const showDeleteModal = () => setIsDeleteModalVisible(true);
|
||||
|
||||
const { status } = useFetcher(() => {
|
||||
if (isDeleting) {
|
||||
return deleteMonitor({ id: configId });
|
||||
}
|
||||
}, [configId, isDeleting]);
|
||||
const showDeleteModal = () => setIsDeleteModalVisible(true);
|
||||
|
||||
const handleDelete = () => {
|
||||
showDeleteModal();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!isDeleting) {
|
||||
return;
|
||||
}
|
||||
if (status === FETCH_STATUS.SUCCESS || status === FETCH_STATUS.FAILURE) {
|
||||
setIsDeleting(false);
|
||||
}
|
||||
if (status === FETCH_STATUS.FAILURE) {
|
||||
kibanaService.toasts.addDanger(
|
||||
{
|
||||
title: toMountPoint(
|
||||
<p data-test-subj="uptimeDeleteMonitorFailure">{MONITOR_DELETE_FAILURE_LABEL}</p>
|
||||
),
|
||||
},
|
||||
{ toastLifeTimeMs: 3000 }
|
||||
);
|
||||
} else if (status === FETCH_STATUS.SUCCESS) {
|
||||
if (isSuccessfullyDeleted) {
|
||||
onUpdate();
|
||||
kibanaService.toasts.addSuccess(
|
||||
{
|
||||
title: toMountPoint(
|
||||
<p data-test-subj="uptimeDeleteMonitorSuccess">
|
||||
{i18n.translate(
|
||||
'xpack.synthetics.monitorManagement.monitorDeleteSuccessMessage.name',
|
||||
{
|
||||
defaultMessage: 'Deleted "{name}"',
|
||||
values: { name },
|
||||
}
|
||||
)}
|
||||
</p>
|
||||
),
|
||||
},
|
||||
{ toastLifeTimeMs: 3000 }
|
||||
);
|
||||
}
|
||||
}, [setIsDeleting, onUpdate, status, name, isDeleting]);
|
||||
}, [onUpdate, isSuccessfullyDeleted]);
|
||||
|
||||
const destroyModal = (
|
||||
<EuiConfirmModal
|
||||
|
@ -121,17 +91,15 @@ export const DeleteMonitor = ({
|
|||
|
||||
return (
|
||||
<>
|
||||
{status === FETCH_STATUS.LOADING ? (
|
||||
<EuiLoadingSpinner size="m" aria-label={MONITOR_DELETE_LOADING_LABEL} />
|
||||
) : (
|
||||
<EuiButtonIcon
|
||||
isDisabled={isDisabled}
|
||||
iconType="trash"
|
||||
onClick={handleDelete}
|
||||
aria-label={DELETE_MONITOR_LABEL}
|
||||
data-test-subj="monitorManagementDeleteMonitor"
|
||||
/>
|
||||
)}
|
||||
<EuiButtonIcon
|
||||
isDisabled={isDisabled}
|
||||
iconType="trash"
|
||||
onClick={handleDelete}
|
||||
aria-label={DELETE_MONITOR_LABEL}
|
||||
data-test-subj="monitorManagementDeleteMonitor"
|
||||
isLoading={isDeleting}
|
||||
/>
|
||||
|
||||
{isDeleteModalVisible && destroyModal}
|
||||
</>
|
||||
);
|
||||
|
@ -151,18 +119,3 @@ const DELETE_MONITOR_LABEL = i18n.translate(
|
|||
defaultMessage: 'Delete monitor',
|
||||
}
|
||||
);
|
||||
|
||||
// TODO: Discuss error states with product
|
||||
const MONITOR_DELETE_FAILURE_LABEL = i18n.translate(
|
||||
'xpack.synthetics.monitorManagement.monitorDeleteFailureMessage',
|
||||
{
|
||||
defaultMessage: 'Monitor was unable to be deleted. Please try again later.',
|
||||
}
|
||||
);
|
||||
|
||||
const MONITOR_DELETE_LOADING_LABEL = i18n.translate(
|
||||
'xpack.synthetics.monitorManagement.monitorDeleteLoadingMessage',
|
||||
{
|
||||
defaultMessage: 'Deleting monitor...',
|
||||
}
|
||||
);
|
||||
|
|
|
@ -180,7 +180,6 @@ export const MonitorManagementList = ({
|
|||
}),
|
||||
sortable: true,
|
||||
render: (urls: string, { hosts }: TCPSimpleFields | ICMPSimpleFields) => urls || hosts,
|
||||
truncateText: true,
|
||||
textOnly: true,
|
||||
},
|
||||
{
|
||||
|
@ -205,6 +204,7 @@ export const MonitorManagementList = ({
|
|||
}),
|
||||
render: (fields: EncryptedSyntheticsMonitorWithId) => (
|
||||
<Actions
|
||||
key={fields[ConfigKey.CONFIG_ID]}
|
||||
configId={fields[ConfigKey.CONFIG_ID]}
|
||||
name={fields[ConfigKey.NAME]}
|
||||
isDisabled={!canEdit}
|
||||
|
|
|
@ -129,4 +129,5 @@ export const mockState: AppState = {
|
|||
},
|
||||
testNowRuns: {},
|
||||
agentPolicies: { loading: false, data: null, error: null },
|
||||
deleteMonitor: {},
|
||||
};
|
||||
|
|
|
@ -16,19 +16,19 @@ import { AppState } from '../../state';
|
|||
import { rootReducer } from '../../state/reducers';
|
||||
import { rootEffect } from '../../state/effects';
|
||||
|
||||
const createRealStore = (): Store => {
|
||||
export const createRealStore = (): Store => {
|
||||
const sagaMW = createSagaMiddleware();
|
||||
const store = createReduxStore(rootReducer, applyMiddleware(sagaMW));
|
||||
sagaMW.run(rootEffect);
|
||||
return store;
|
||||
};
|
||||
|
||||
export const MountWithReduxProvider: React.FC<{ state?: AppState; useRealStore?: boolean }> = ({
|
||||
children,
|
||||
state,
|
||||
useRealStore,
|
||||
}) => {
|
||||
const store = useRealStore
|
||||
export const MountWithReduxProvider: React.FC<{
|
||||
state?: AppState;
|
||||
useRealStore?: boolean;
|
||||
store?: Store;
|
||||
}> = ({ children, state, store, useRealStore }) => {
|
||||
const newStore = useRealStore
|
||||
? createRealStore()
|
||||
: {
|
||||
dispatch: jest.fn(),
|
||||
|
@ -38,5 +38,5 @@ export const MountWithReduxProvider: React.FC<{ state?: AppState; useRealStore?:
|
|||
[Symbol.observable]: jest.fn(),
|
||||
};
|
||||
|
||||
return <ReduxProvider store={store}>{children}</ReduxProvider>;
|
||||
return <ReduxProvider store={store ?? newStore}>{children}</ReduxProvider>;
|
||||
};
|
||||
|
|
|
@ -28,6 +28,7 @@ import { KibanaContextProvider, KibanaServices } from '@kbn/kibana-react-plugin/
|
|||
import { triggersActionsUiMock } from '@kbn/triggers-actions-ui-plugin/public/mocks';
|
||||
import { dataPluginMock } from '@kbn/data-plugin/public/mocks';
|
||||
import { unifiedSearchPluginMock } from '@kbn/unified-search-plugin/public/mocks';
|
||||
import { Store } from 'redux';
|
||||
import { mockState } from '../__mocks__/uptime_store.mock';
|
||||
import { MountWithReduxProvider } from './helper_with_redux';
|
||||
import { AppState } from '../../state';
|
||||
|
@ -221,12 +222,17 @@ export function WrappedHelper<ExtraCore>({
|
|||
url,
|
||||
useRealStore,
|
||||
path,
|
||||
store,
|
||||
history = createMemoryHistory(),
|
||||
}: RenderRouterOptions<ExtraCore> & { children: ReactElement; useRealStore?: boolean }) {
|
||||
}: RenderRouterOptions<ExtraCore> & {
|
||||
children: ReactElement;
|
||||
useRealStore?: boolean;
|
||||
store?: Store;
|
||||
}) {
|
||||
const testState: AppState = merge({}, mockState, state);
|
||||
|
||||
return (
|
||||
<MountWithReduxProvider state={testState} useRealStore={useRealStore}>
|
||||
<MountWithReduxProvider state={testState} useRealStore={useRealStore} store={store}>
|
||||
<MockRouter path={path} history={history} kibanaProps={kibanaProps} core={core}>
|
||||
{children}
|
||||
</MockRouter>
|
||||
|
@ -246,7 +252,8 @@ export function render<ExtraCore>(
|
|||
url,
|
||||
path,
|
||||
useRealStore,
|
||||
}: RenderRouterOptions<ExtraCore> & { useRealStore?: boolean } = {}
|
||||
store,
|
||||
}: RenderRouterOptions<ExtraCore> & { useRealStore?: boolean; store?: Store } = {}
|
||||
): any {
|
||||
if (url) {
|
||||
history = getHistoryFromUrl(url);
|
||||
|
@ -262,6 +269,7 @@ export function render<ExtraCore>(
|
|||
state={state}
|
||||
path={path}
|
||||
useRealStore={useRealStore}
|
||||
store={store}
|
||||
>
|
||||
{ui}
|
||||
</WrappedHelper>,
|
||||
|
|
|
@ -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 { createAsyncAction } from './utils';
|
||||
|
||||
export const deleteMonitorAction = createAsyncAction<
|
||||
{ id: string; name: string },
|
||||
string,
|
||||
{ id: string; error: Error }
|
||||
>('DELETE_MONITOR');
|
|
@ -10,13 +10,13 @@ import type { IHttpFetchError } from '@kbn/core-http-browser';
|
|||
import type { Rule } from '@kbn/triggers-actions-ui-plugin/public';
|
||||
import type { UptimeAlertTypeParams } from '../alerts/alerts';
|
||||
|
||||
export interface AsyncAction<Payload, SuccessPayload> {
|
||||
export interface AsyncAction<Payload, SuccessPayload, ErrorPayload = IHttpFetchError> {
|
||||
get: (payload: Payload) => Action<Payload>;
|
||||
success: (payload: SuccessPayload) => Action<SuccessPayload>;
|
||||
fail: (payload: IHttpFetchError) => Action<IHttpFetchError>;
|
||||
fail: (payload: ErrorPayload) => Action<ErrorPayload>;
|
||||
}
|
||||
export interface AsyncActionOptionalPayload<Payload, SuccessPayload>
|
||||
extends AsyncAction<Payload, SuccessPayload> {
|
||||
export interface AsyncActionOptionalPayload<Payload, SuccessPayload, ErrorPayload>
|
||||
extends AsyncAction<Payload, SuccessPayload, ErrorPayload> {
|
||||
get: (payload?: Payload) => Action<Payload>;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,15 +9,15 @@ import { createAction } from 'redux-actions';
|
|||
import type { IHttpFetchError } from '@kbn/core-http-browser';
|
||||
import type { AsyncAction, AsyncActionOptionalPayload } from './types';
|
||||
|
||||
export function createAsyncAction<Payload, SuccessPayload>(
|
||||
export function createAsyncAction<Payload, SuccessPayload, ErrorPayload = IHttpFetchError>(
|
||||
actionStr: string
|
||||
): AsyncActionOptionalPayload<Payload, SuccessPayload>;
|
||||
export function createAsyncAction<Payload, SuccessPayload>(
|
||||
): AsyncActionOptionalPayload<Payload, SuccessPayload, ErrorPayload>;
|
||||
export function createAsyncAction<Payload, SuccessPayload, ErrorPayload = IHttpFetchError>(
|
||||
actionStr: string
|
||||
): AsyncAction<Payload, SuccessPayload> {
|
||||
): AsyncAction<Payload, SuccessPayload, ErrorPayload> {
|
||||
return {
|
||||
get: createAction<Payload>(actionStr),
|
||||
success: createAction<SuccessPayload>(`${actionStr}_SUCCESS`),
|
||||
fail: createAction<IHttpFetchError>(`${actionStr}_FAIL`),
|
||||
fail: createAction<ErrorPayload>(`${actionStr}_FAIL`),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* 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 React from 'react';
|
||||
import { toMountPoint } from '@kbn/kibana-react-plugin/public';
|
||||
import { put, call, takeEvery } from 'redux-saga/effects';
|
||||
import { Action } from 'redux-actions';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { deleteMonitorAction } from '../actions/delete_monitor';
|
||||
import { deleteMonitor } from '../api';
|
||||
import { kibanaService } from '../kibana_service';
|
||||
|
||||
export function* deleteMonitorEffect() {
|
||||
yield takeEvery(
|
||||
String(deleteMonitorAction.get),
|
||||
function* (action: Action<{ id: string; name: string }>) {
|
||||
try {
|
||||
const { id, name } = action.payload;
|
||||
yield call(deleteMonitor, { id });
|
||||
yield put(deleteMonitorAction.success(id));
|
||||
kibanaService.core.notifications.toasts.addSuccess({
|
||||
title: toMountPoint(
|
||||
<p data-test-subj="uptimeDeleteMonitorSuccess">
|
||||
{i18n.translate(
|
||||
'xpack.synthetics.monitorManagement.monitorDeleteSuccessMessage.name',
|
||||
{
|
||||
defaultMessage: 'Deleted "{name}"',
|
||||
values: { name },
|
||||
}
|
||||
)}
|
||||
</p>
|
||||
),
|
||||
});
|
||||
} catch (err) {
|
||||
kibanaService.core.notifications.toasts.addError(err, {
|
||||
title: MONITOR_DELETE_FAILURE_LABEL,
|
||||
});
|
||||
yield put(deleteMonitorAction.fail({ id: action.payload.id, error: err }));
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const MONITOR_DELETE_FAILURE_LABEL = i18n.translate(
|
||||
'xpack.synthetics.monitorManagement.monitorDeleteFailureMessage',
|
||||
{
|
||||
defaultMessage: 'Monitor was unable to be deleted. Please try again later.',
|
||||
}
|
||||
);
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
import { fork } from 'redux-saga/effects';
|
||||
import { deleteMonitorEffect } from './delete_monitor';
|
||||
import { fetchAgentPoliciesEffect } from '../private_locations';
|
||||
import { fetchMonitorDetailsEffect } from './monitor';
|
||||
import { fetchMonitorListEffect, fetchUpdatedMonitorEffect } from './monitor_list';
|
||||
|
@ -51,4 +52,5 @@ export function* rootEffect() {
|
|||
yield fork(pruneBlockCache);
|
||||
yield fork(fetchSyntheticsServiceAllowedEffect);
|
||||
yield fork(fetchAgentPoliciesEffect);
|
||||
yield fork(deleteMonitorEffect);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* 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 { createReducer, PayloadAction } from '@reduxjs/toolkit';
|
||||
import { WritableDraft } from 'immer/dist/types/types-external';
|
||||
import { deleteMonitorAction } from '../actions/delete_monitor';
|
||||
|
||||
export interface DeleteMonitorState {
|
||||
error?: Record<string, Error | undefined>;
|
||||
loading?: string[];
|
||||
deletedMonitorIds?: string[];
|
||||
}
|
||||
|
||||
export const initialState: DeleteMonitorState = {
|
||||
error: {},
|
||||
loading: [],
|
||||
deletedMonitorIds: [],
|
||||
};
|
||||
|
||||
export const deleteMonitorReducer = createReducer(initialState, (builder) => {
|
||||
builder
|
||||
.addCase(
|
||||
String(deleteMonitorAction.get),
|
||||
(
|
||||
state: WritableDraft<DeleteMonitorState>,
|
||||
action: PayloadAction<{ id: string; name: string }>
|
||||
) => ({
|
||||
...state,
|
||||
loading: [...(state.loading ?? []), action.payload.id],
|
||||
error: { ...state.error, [action.payload.id]: undefined },
|
||||
})
|
||||
)
|
||||
.addCase(
|
||||
String(deleteMonitorAction.success),
|
||||
(state: WritableDraft<DeleteMonitorState>, action: PayloadAction<string>) => ({
|
||||
...state,
|
||||
loading: state.loading?.filter((id) => id !== action.payload),
|
||||
deletedMonitorIds: [...(state.deletedMonitorIds ?? []), action.payload],
|
||||
})
|
||||
)
|
||||
.addCase(
|
||||
String(deleteMonitorAction.fail),
|
||||
(
|
||||
state: WritableDraft<DeleteMonitorState>,
|
||||
action: PayloadAction<{ id: string; error: Error }>
|
||||
) => ({
|
||||
...state,
|
||||
loading: state.loading?.filter((id) => id !== action.payload.id),
|
||||
error: { ...state.error, [action.payload.id]: action.payload.error },
|
||||
})
|
||||
);
|
||||
});
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
import { combineReducers } from 'redux';
|
||||
import { deleteMonitorReducer, DeleteMonitorState } from './delete_monitor';
|
||||
import { agentPoliciesReducer, AgentPoliciesState } from '../private_locations';
|
||||
import { monitorReducer, MonitorState } from './monitor';
|
||||
import { uiReducer, UiState } from './ui';
|
||||
|
@ -47,6 +48,7 @@ export interface RootState {
|
|||
synthetics: SyntheticsReducerState;
|
||||
testNowRuns: TestNowRunsState;
|
||||
agentPolicies: AgentPoliciesState;
|
||||
deleteMonitor: DeleteMonitorState;
|
||||
}
|
||||
|
||||
export const rootReducer = combineReducers<RootState>({
|
||||
|
@ -69,4 +71,5 @@ export const rootReducer = combineReducers<RootState>({
|
|||
synthetics: syntheticsReducer,
|
||||
testNowRuns: testNowRunsReducer,
|
||||
agentPolicies: agentPoliciesReducer,
|
||||
deleteMonitor: deleteMonitorReducer,
|
||||
});
|
||||
|
|
|
@ -19,6 +19,15 @@ export const monitorDetailsSelector = (state: AppState, summary: any) => {
|
|||
return state.monitor.monitorDetailsList[summary.monitor_id];
|
||||
};
|
||||
|
||||
export const deleteMonitorLoadingSelector = (state: AppState, id?: string) => {
|
||||
if (!id) return (state.deleteMonitor.loading ?? []).length > 0;
|
||||
return state.deleteMonitor.loading?.includes(id) ?? false;
|
||||
};
|
||||
|
||||
export const deleteMonitorSuccessSelector = (state: AppState, id: string) => {
|
||||
return state.deleteMonitor.deletedMonitorIds?.includes(id) ?? false;
|
||||
};
|
||||
|
||||
export const monitorDetailsLoadingSelector = (state: AppState) => state.monitor.loading;
|
||||
|
||||
export const monitorLocationsSelector = (state: AppState, monitorId: string) => {
|
||||
|
|
|
@ -31082,7 +31082,6 @@
|
|||
"xpack.synthetics.monitorManagement.monitorAdvancedOptions.monitorNamespaceFieldLabel": "Espace de nom",
|
||||
"xpack.synthetics.monitorManagement.monitorAdvancedOptions.namespaceHelpLearnMoreLabel": "En savoir plus",
|
||||
"xpack.synthetics.monitorManagement.monitorDeleteFailureMessage": "Impossible de supprimer le moniteur. Réessayez plus tard.",
|
||||
"xpack.synthetics.monitorManagement.monitorDeleteLoadingMessage": "Suppression du moniteur...",
|
||||
"xpack.synthetics.monitorManagement.monitorEditedSuccessMessage": "Moniteur mis à jour.",
|
||||
"xpack.synthetics.monitorManagement.monitorFailureMessage": "Impossible d'enregistrer le moniteur. Réessayez plus tard.",
|
||||
"xpack.synthetics.monitorManagement.monitorList.actions": "Actions",
|
||||
|
|
|
@ -31058,7 +31058,6 @@
|
|||
"xpack.synthetics.monitorManagement.monitorAdvancedOptions.monitorNamespaceFieldLabel": "名前空間",
|
||||
"xpack.synthetics.monitorManagement.monitorAdvancedOptions.namespaceHelpLearnMoreLabel": "詳細情報",
|
||||
"xpack.synthetics.monitorManagement.monitorDeleteFailureMessage": "モニターを削除できませんでした。しばらくたってから再試行してください。",
|
||||
"xpack.synthetics.monitorManagement.monitorDeleteLoadingMessage": "モニターを削除しています...",
|
||||
"xpack.synthetics.monitorManagement.monitorEditedSuccessMessage": "モニターは正常に更新されました。",
|
||||
"xpack.synthetics.monitorManagement.monitorFailureMessage": "モニターを保存できませんでした。しばらくたってから再試行してください。",
|
||||
"xpack.synthetics.monitorManagement.monitorList.actions": "アクション",
|
||||
|
|
|
@ -31093,7 +31093,6 @@
|
|||
"xpack.synthetics.monitorManagement.monitorAdvancedOptions.monitorNamespaceFieldLabel": "命名空间",
|
||||
"xpack.synthetics.monitorManagement.monitorAdvancedOptions.namespaceHelpLearnMoreLabel": "了解详情",
|
||||
"xpack.synthetics.monitorManagement.monitorDeleteFailureMessage": "无法删除监测。请稍后重试。",
|
||||
"xpack.synthetics.monitorManagement.monitorDeleteLoadingMessage": "正在删除监测......",
|
||||
"xpack.synthetics.monitorManagement.monitorEditedSuccessMessage": "已成功更新监测。",
|
||||
"xpack.synthetics.monitorManagement.monitorFailureMessage": "无法保存监测。请稍后重试。",
|
||||
"xpack.synthetics.monitorManagement.monitorList.actions": "操作",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue