Skip to content

Commit

Permalink
[Synthetics] Isolate Add/Edit API routes HTTP interface from SavedObj…
Browse files Browse the repository at this point in the history
…ect type (elastic#162519)

Co-authored-by: kibanamachine <[email protected]>
Co-authored-by: Shahzad <[email protected]>
  • Loading branch information
3 people authored Jul 31, 2023
1 parent 8749d5f commit d7e16b3
Show file tree
Hide file tree
Showing 27 changed files with 240 additions and 180 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -138,10 +138,16 @@ export type ManifestLocation = t.TypeOf<typeof ManifestLocationCodec>;
export type ServiceLocation = t.TypeOf<typeof ServiceLocationCodec>;
export type ServiceLocations = t.TypeOf<typeof ServiceLocationsCodec>;
export type MonitorServiceLocation = t.TypeOf<typeof MonitorServiceLocationCodec>;
export type MonitorServiceLocations = t.TypeOf<typeof MonitorServiceLocationsCodec>;
export type ServiceLocationsApiResponse = t.TypeOf<typeof ServiceLocationsApiResponseCodec>;
export type ServiceLocationErrors = t.TypeOf<typeof ServiceLocationErrors>;
export type ThrottlingOptions = t.TypeOf<typeof ThrottlingOptionsCodec>;
export type Locations = t.TypeOf<typeof LocationsCodec>;
export type PublicLocation = t.TypeOf<typeof PublicLocationCodec>;
export type PublicLocations = t.TypeOf<typeof PublicLocationsCodec>;

export interface ServiceLocationErrorsResponse {
attributes: { message: string; errors: ServiceLocationErrors; id?: string };
}

// TODO: Remove if not needed
// export type MonitorServiceLocations = t.TypeOf<typeof MonitorServiceLocationsCodec>;
// export type ServiceLocationsApiResponse = t.TypeOf<typeof ServiceLocationsApiResponseCodec>;
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ import { useDispatch, useSelector } from 'react-redux';
import { useSyntheticsRefreshContext } from '../../contexts';
import { cleanMonitorListState, selectServiceLocationsState } from '../../state';
import { showSyncErrors } from '../monitors_page/management/show_sync_errors';
import { createGettingStartedMonitor } from '../../state';
import { createGettingStartedMonitor, UpsertMonitorResponse } from '../../state';
import { DEFAULT_FIELDS } from '../../../../../common/constants/monitor_defaults';
import { ConfigKey } from '../../../../../common/constants/monitor_management';
import {
DataStream,
EncryptedSyntheticsSavedMonitor,
ServiceLocationErrors,
SyntheticsMonitorWithId,
} from '../../../../../common/runtime_types';
import {
MONITOR_SUCCESS_LABEL,
Expand Down Expand Up @@ -56,7 +56,7 @@ export const useSimpleMonitor = ({ monitorData }: { monitorData?: SimpleFormData
}, [monitorData]);

useEffect(() => {
const newMonitor = data as SyntheticsMonitorWithId;
const newMonitor = data as UpsertMonitorResponse;
const hasErrors = data && 'attributes' in data && data.attributes.errors?.length > 0;
if (hasErrors && !loading) {
showSyncErrors(
Expand All @@ -71,7 +71,7 @@ export const useSimpleMonitor = ({ monitorData }: { monitorData?: SimpleFormData
title: MONITOR_FAILURE_LABEL,
toastLifeTimeMs: 3000,
});
} else if (!loading && newMonitor?.id) {
} else if (!loading && (newMonitor as EncryptedSyntheticsSavedMonitor)?.id) {
kibanaService.toasts.addSuccess({
title: MONITOR_SUCCESS_LABEL,
toastLifeTimeMs: 3000,
Expand All @@ -82,5 +82,5 @@ export const useSimpleMonitor = ({ monitorData }: { monitorData?: SimpleFormData
}
}, [application, data, status, dispatch, loading, refreshApp, serviceLocations]);

return { data: data as SyntheticsMonitorWithId, loading };
return { data: data as EncryptedSyntheticsSavedMonitor, loading };
};
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,11 @@ export const MonitorDetailsPanelContainer = (props: Partial<MonitorDetailsPanelP

const { monitor, loading } = useSelectedMonitor();

if (
(latestPing && latestPing?.config_id !== configId) ||
(monitor && monitor[ConfigKey.CONFIG_ID] !== configId)
) {
const isPingRelevant =
latestPing?.config_id === monitor?.[ConfigKey.CONFIG_ID] ||
latestPing?.monitor?.id === monitor?.[ConfigKey.MONITOR_QUERY_ID];

if (!monitor || !isPingRelevant) {
return <EuiSkeletonText lines={6} />;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { useSelector } from 'react-redux';
import { useMemo } from 'react';
import { useEsSearch } from '@kbn/observability-shared-plugin/public';
import { selectEncryptedSyntheticsSavedMonitors } from '../../../state';
import { Ping } from '../../../../../../common/runtime_types';
import { ConfigKey, Ping } from '../../../../../../common/runtime_types';
import {
EXCLUDE_RUN_ONCE_FILTER,
getTimeSpanFilter,
Expand Down Expand Up @@ -70,7 +70,7 @@ export function useInlineErrors({

const { lastRefresh } = useSyntheticsRefreshContext();

const configIds = syntheticsMonitors.map((monitor) => monitor.id);
const configIds = syntheticsMonitors.map((monitor) => monitor[ConfigKey.CONFIG_ID]);

const doFetch = configIds.length > 0 || onlyInvalidMonitors;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ export function MonitorDetailFlyout(props: Props) {
const upsertSuccess = upsertStatus?.status === 'success';

const {
data: monitorSavedObject,
data: monitorObject,
error,
status,
loading,
Expand All @@ -262,7 +262,7 @@ export function MonitorDetailFlyout(props: Props) {
const monitorDetail = useMonitorDetail(configId, props.location);
const { locations } = useStatusByLocation({
configId,
monitorLocations: monitorSavedObject?.locations,
monitorLocations: monitorObject?.locations,
});

const isOverlay = useIsWithinMaxBreakpoint('xl');
Expand All @@ -276,14 +276,14 @@ export function MonitorDetailFlyout(props: Props) {
>
{status === FETCH_STATUS.FAILURE && <EuiErrorBoundary>{error?.message}</EuiErrorBoundary>}
{status === FETCH_STATUS.LOADING && <LoadingState />}
{status === FETCH_STATUS.SUCCESS && monitorSavedObject && (
{status === FETCH_STATUS.SUCCESS && monitorObject && (
<>
<EuiFlyoutHeader hasBorder>
<EuiPanel hasBorder={false} hasShadow={false} paddingSize="l">
<EuiFlexGroup responsive={false} gutterSize="s">
<EuiFlexItem grow={false}>
<EuiTitle size="s">
<h2>{monitorSavedObject?.[ConfigKey.NAME]}</h2>
<h2>{monitorObject?.[ConfigKey.NAME]}</h2>
</EuiTitle>
</EuiFlexItem>
<EuiFlexItem grow={false}>
Expand All @@ -307,7 +307,7 @@ export function MonitorDetailFlyout(props: Props) {
locations={locations}
setCurrentLocation={setLocation}
configId={configId}
monitor={monitorSavedObject}
monitor={monitorObject}
onEnabledChange={props.onEnabledChange}
/>
</EuiPanel>
Expand All @@ -320,10 +320,8 @@ export function MonitorDetailFlyout(props: Props) {
latestPing={monitorDetail.data}
configId={configId}
monitor={{
...monitorSavedObject,
...monitorObject,
id,
updated_at: monitorSavedObject.updated_at!,
created_at: monitorSavedObject.created_at!,
}}
loading={Boolean(loading)}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,5 @@ export * from './overview';
export * from './browser_journey';
export * from './ping_status';
export * from './private_locations';

export type { UpsertMonitorResponse } from './monitor_management/api';
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ export const monitorDetailsReducer = createReducer(initialState, (builder) => {
})
.addCase(enableMonitorAlertAction.success, (state, action) => {
if ('updated_at' in action.payload && state.syntheticsMonitor) {
state.syntheticsMonitor = action.payload.attributes as EncryptedSyntheticsSavedMonitor;
state.syntheticsMonitor = action.payload;
}
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
*/

import { createAction } from '@reduxjs/toolkit';
import { UpsertMonitorError, UpsertMonitorRequest, UpsertMonitorResponse } from '..';
import { UpsertMonitorError, UpsertMonitorRequest } from '..';
import {
MonitorManagementListResult,
MonitorFiltersResult,
EncryptedSyntheticsSavedMonitor,
} from '../../../../../common/runtime_types';
import { createAsyncAction } from '../utils/actions';

Expand All @@ -24,17 +25,16 @@ export const quietFetchMonitorListAction = createAction<MonitorListPageState>(
);

export const fetchUpsertMonitorAction = createAction<UpsertMonitorRequest>('fetchUpsertMonitor');
export const fetchUpsertSuccessAction = createAction<{
id: string;
attributes: { enabled: boolean };
}>('fetchUpsertMonitorSuccess');
export const fetchUpsertSuccessAction = createAction<EncryptedSyntheticsSavedMonitor>(
'fetchUpsertMonitorSuccess'
);
export const fetchUpsertFailureAction = createAction<UpsertMonitorError>(
'fetchUpsertMonitorFailure'
);

export const enableMonitorAlertAction = createAsyncAction<
UpsertMonitorRequest,
UpsertMonitorResponse,
EncryptedSyntheticsSavedMonitor,
UpsertMonitorError
>('enableMonitorAlertAction');

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@
* 2.0.
*/

import { SavedObject } from '@kbn/core-saved-objects-common';
import { UpsertMonitorRequest } from '..';
import { UpsertMonitorResponse } from '../monitor_management/api';
import { SYNTHETICS_API_URLS } from '../../../../../common/constants';
import {
EncryptedSyntheticsMonitor,
FetchMonitorManagementListQueryArgs,
MonitorManagementListResult,
MonitorManagementListResultCodec,
ServiceLocationErrors,
SyntheticsMonitor,
MonitorFiltersResult,
} from '../../../../../common/runtime_types';
Expand Down Expand Up @@ -56,10 +55,6 @@ export const fetchDeleteMonitor = async ({ configId }: { configId: string }): Pr
return await apiService.delete(`${SYNTHETICS_API_URLS.SYNTHETICS_MONITORS}/${configId}`);
};

export type UpsertMonitorResponse =
| { attributes: { errors: ServiceLocationErrors }; id: string }
| SavedObject<SyntheticsMonitor>;

export const fetchUpsertMonitor = async ({
monitor,
configId,
Expand All @@ -75,7 +70,7 @@ export const createGettingStartedMonitor = async ({
monitor,
}: {
monitor: SyntheticsMonitor | EncryptedSyntheticsMonitor;
}): Promise<{ attributes: { errors: ServiceLocationErrors } } | SyntheticsMonitor> => {
}): Promise<UpsertMonitorResponse> => {
return await apiService.post(SYNTHETICS_API_URLS.SYNTHETICS_MONITORS, monitor, undefined, {
gettingStarted: true,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@

import { PayloadAction } from '@reduxjs/toolkit';
import { call, put, takeEvery, select, takeLatest, debounce } from 'redux-saga/effects';
import { SavedObject } from '@kbn/core-saved-objects-common';
import { quietFetchOverviewStatusAction } from '../overview_status';
import { enableDefaultAlertingAction } from '../alert_rules';
import { ConfigKey, SyntheticsMonitor } from '../../../../../common/runtime_types';
import { ConfigKey, EncryptedSyntheticsSavedMonitor } from '../../../../../common/runtime_types';
import { kibanaService } from '../../../../utils/kibana_service';
import { MonitorOverviewPageState } from '../overview';
import { quietFetchOverviewAction } from '../overview/actions';
Expand All @@ -27,12 +26,8 @@ import {
quietFetchMonitorListAction,
fetchMonitorFiltersAction,
} from './actions';
import {
fetchMonitorManagementList,
fetchUpsertMonitor,
fetchMonitorFilters,
UpsertMonitorResponse,
} from './api';
import { fetchMonitorManagementList, fetchUpsertMonitor, fetchMonitorFilters } from './api';

import { toastTitle } from './toast_title';
import { UpsertMonitorRequest } from './models';

Expand All @@ -54,11 +49,10 @@ export function* enableMonitorAlertEffect() {
function* (action: PayloadAction<UpsertMonitorRequest>): Generator {
try {
const response = yield call(fetchUpsertMonitor, action.payload);
yield put(enableMonitorAlertAction.success(response as UpsertMonitorResponse));
yield put(enableMonitorAlertAction.success(response as EncryptedSyntheticsSavedMonitor));
sendSuccessToast(action.payload.success);
if (
(response as SavedObject<SyntheticsMonitor>).attributes[ConfigKey.ALERT_CONFIG]?.status
?.enabled
(response as EncryptedSyntheticsSavedMonitor)[ConfigKey.ALERT_CONFIG]?.status?.enabled
) {
yield put(enableDefaultAlertingAction.get());
}
Expand All @@ -81,9 +75,7 @@ export function* upsertMonitorEffect() {
function* (action: PayloadAction<UpsertMonitorRequest>): Generator {
try {
const response = yield call(fetchUpsertMonitor, action.payload);
yield put(
fetchUpsertSuccessAction(response as { id: string; attributes: { enabled: boolean } })
);
yield put(fetchUpsertSuccessAction(response as EncryptedSyntheticsSavedMonitor));
kibanaService.toasts.addSuccess({
title: toastTitle({
title: action.payload.success.message,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,9 @@ export const monitorListReducer = createReducer(initialState, (builder) => {
};
})
.addCase(fetchUpsertSuccessAction, (state, action) => {
state.monitorUpsertStatuses[action.payload.id] = {
state.monitorUpsertStatuses[action.payload.config_id] = {
status: FETCH_STATUS.SUCCESS,
enabled: action.payload.attributes.enabled,
enabled: action.payload.enabled,
};
})
.addCase(fetchUpsertFailureAction, (state, action) => {
Expand All @@ -94,15 +94,15 @@ export const monitorListReducer = createReducer(initialState, (builder) => {
};
})
.addCase(enableMonitorAlertAction.success, (state, action) => {
state.monitorUpsertStatuses[action.payload.id] = {
...state.monitorUpsertStatuses[action.payload.id],
state.monitorUpsertStatuses[action.payload.config_id] = {
...state.monitorUpsertStatuses[action.payload.config_id],
alertStatus: FETCH_STATUS.SUCCESS,
};
if ('updated_at' in action.payload) {
state.data.monitors = state.data.monitors.map<EncryptedSyntheticsSavedMonitor>(
(monitor: any) => {
if (monitor.config_id === action.payload.id) {
return action.payload.attributes;
if (monitor.config_id === action.payload.config_id) {
return action.payload;
}
return monitor;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,19 @@ import { PackagePolicy } from '@kbn/fleet-plugin/common';
import { apiService } from '../../../../utils/api_service';
import {
EncryptedSyntheticsMonitor,
ServiceLocationErrors,
SyntheticsMonitor,
SyntheticsMonitorWithId,
SyntheticsMonitorCodec,
ServiceLocationErrorsResponse,
} from '../../../../../common/runtime_types';
import { SYNTHETICS_API_URLS } from '../../../../../common/constants';

export type UpsertMonitorResponse = ServiceLocationErrorsResponse | EncryptedSyntheticsMonitor;

export const createMonitorAPI = async ({
monitor,
}: {
monitor: SyntheticsMonitor | EncryptedSyntheticsMonitor;
}): Promise<{ attributes: { errors: ServiceLocationErrors } } | SyntheticsMonitor> => {
}): Promise<UpsertMonitorResponse> => {
return await apiService.post(SYNTHETICS_API_URLS.SYNTHETICS_MONITORS, monitor);
};

Expand All @@ -47,7 +48,7 @@ export const updateMonitorAPI = async ({
}: {
monitor: SyntheticsMonitor | EncryptedSyntheticsMonitor;
id: string;
}): Promise<{ attributes: { errors: ServiceLocationErrors } } | SyntheticsMonitorWithId> => {
}): Promise<UpsertMonitorResponse> => {
return await apiService.put(`${SYNTHETICS_API_URLS.SYNTHETICS_MONITORS}/${id}`, monitor);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,13 @@ export const monitorOverviewReducer = createReducer(initialState, (builder) => {
state.flyoutConfig = action.payload;
})
.addCase(enableMonitorAlertAction.success, (state, action) => {
const attrs = action.payload.attributes;
if (!('errors' in attrs)) {
const isStatusAlertEnabled = isStatusEnabled(attrs[ConfigKey.ALERT_CONFIG]);
const monitorObject = action.payload;
if (!('errors' in monitorObject)) {
const isStatusAlertEnabled = isStatusEnabled(monitorObject[ConfigKey.ALERT_CONFIG]);
state.data.monitors = state.data.monitors.map((monitor) => {
if (
monitor.id === action.payload.id ||
attrs[ConfigKey.MONITOR_QUERY_ID] === monitor.id
monitor.id === monitorObject[ConfigKey.CONFIG_ID] ||
monitor.id === monitorObject[ConfigKey.MONITOR_QUERY_ID]
) {
return {
...monitor,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import { validateMonitor } from './monitor_validation';
import { sendTelemetryEvents, formatTelemetryEvent } from '../telemetry/monitor_upgrade_sender';
import { formatSecrets } from '../../synthetics_service/utils/secrets';
import { deleteMonitor } from './delete_monitor';
import { mapSavedObjectToMonitor } from './helper';

export const addSyntheticsMonitorRoute: SyntheticsRestApiRouteFactory = () => ({
method: 'POST',
Expand Down Expand Up @@ -96,7 +97,7 @@ export const addSyntheticsMonitorRoute: SyntheticsRestApiRouteFactory = () => ({
initDefaultAlerts(newMonitor.attributes.name, routeContext);
setupGettingStarted(newMonitor.id, routeContext);

return response.ok({ body: newMonitor });
return response.ok({ body: mapSavedObjectToMonitor(newMonitor) });
} catch (getErr) {
server.logger.error(getErr);
if (SavedObjectsErrorHelpers.isForbiddenError(getErr)) {
Expand Down
Loading

0 comments on commit d7e16b3

Please sign in to comment.