Skip to content

Commit

Permalink
[Synthetics] Group by location, type, tag and project !! (elastic#150025
Browse files Browse the repository at this point in the history
  • Loading branch information
shahzad31 authored Feb 3, 2023
1 parent 62d3484 commit 7288b84
Show file tree
Hide file tree
Showing 62 changed files with 1,516 additions and 543 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export enum SYNTHETICS_API_URLS {
SYNTHETICS_OVERVIEW = '/internal/synthetics/overview',
PINGS = '/internal/synthetics/pings',
PING_STATUSES = '/internal/synthetics/ping_statuses',
OVERVIEW_STATUS = `/internal/synthetics/overview/status`,
OVERVIEW_STATUS = `/internal/synthetics/overview_status`,
INDEX_SIZE = `/internal/synthetics/index_size`,
PARAMS = `/synthetics/params`,
SYNC_GLOBAL_PARAMS = `/synthetics/sync_global_params`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -395,14 +395,21 @@ export const MonitorManagementListResultCodec = t.type({

export type MonitorManagementListResult = t.TypeOf<typeof MonitorManagementListResultCodec>;

export const MonitorOverviewItemCodec = t.interface({
name: t.string,
id: t.string,
configId: t.string,
location: MonitorServiceLocationCodec,
isEnabled: t.boolean,
isStatusAlertEnabled: t.boolean,
});
export const MonitorOverviewItemCodec = t.intersection([
t.interface({
name: t.string,
id: t.string,
configId: t.string,
location: MonitorServiceLocationCodec,
isEnabled: t.boolean,
isStatusAlertEnabled: t.boolean,
type: t.string,
tags: t.array(t.string),
}),
t.partial({
projectId: t.string,
}),
]);

export type MonitorOverviewItem = t.TypeOf<typeof MonitorOverviewItemCodec>;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ const createMonitorJourney = ({
journey(
`SyntheticsAddMonitor - ${monitorName}`,
async ({ page, params }: { page: Page; params: any }) => {
page.setDefaultTimeout(60 * 1000);
recordVideo(page);

const syntheticsApp = syntheticsAppPageProvider({ page, kibanaUrl: params.kibanaUrl });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ export const ErrorDetailsButton = ({
stateId: string;
label?: string;
}) => {
const link = useErrorDetailsLink({ configId, stateId });
const selectedLocation = useSelectedLocation();
const link = useErrorDetailsLink({ configId, stateId, locationId: selectedLocation?.id });

return (
<EuiButtonEmpty flush="left" iconType="alert" color="danger" href={link}>
Expand All @@ -47,18 +48,19 @@ export const ErrorDetailsButton = ({
export const useErrorDetailsLink = ({
stateId,
configId,
locationId,
}: {
configId: string;
stateId: string;
locationId?: string;
}) => {
const { basePath } = useSyntheticsSettingsContext();
const selectedLocation = useSelectedLocation();

return getErrorDetailsUrl({
basePath,
configId,
stateId,
locationId: selectedLocation?.id,
locationId,
});
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
import { useFetcher } from '@kbn/observability-plugin/public';
import { useEffect } from 'react';
import { useKibana } from '@kbn/kibana-react-plugin/public';
import { useSelector } from 'react-redux';
import { useDispatch, useSelector } from 'react-redux';
import { useSyntheticsRefreshContext } from '../../contexts';
import { selectServiceLocationsState } from '../../state';
import { cleanMonitorListState, selectServiceLocationsState } from '../../state';
import { showSyncErrors } from '../monitors_page/management/show_sync_errors';
import { fetchCreateMonitor } from '../../state';
import { DEFAULT_FIELDS } from '../../../../../common/constants/monitor_defaults';
Expand All @@ -27,6 +27,8 @@ export const useSimpleMonitor = ({ monitorData }: { monitorData?: SimpleFormData
const { application } = useKibana().services;
const { locations: serviceLocations } = useSelector(selectServiceLocationsState);

const dispatch = useDispatch();

const { refreshApp } = useSyntheticsRefreshContext();

const { data, loading } = useFetcher(() => {
Expand Down Expand Up @@ -66,9 +68,10 @@ export const useSimpleMonitor = ({ monitorData }: { monitorData?: SimpleFormData
toastLifeTimeMs: 3000,
});
refreshApp();
dispatch(cleanMonitorListState());
application?.navigateToApp('synthetics', { path: 'monitors' });
}
}, [application, data, loading, refreshApp, serviceLocations]);
}, [application, data, dispatch, loading, refreshApp, serviceLocations]);

return { data: data as SyntheticsMonitorWithId, loading };
};
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { invert } from 'lodash';
import { DataStream, ServiceLocations } from '../../../../../../../common/runtime_types';
import { MonitorFilterState } from '../../../../state';

export type SyntheticsMonitorFilterField = keyof MonitorFilterState;
export type SyntheticsMonitorFilterField = keyof Omit<MonitorFilterState, 'query'>;

export interface LabelWithCountValue {
label: string;
Expand Down Expand Up @@ -83,7 +83,7 @@ export const valueToLabelWithEmptyCount = (value: string): LabelWithCountValue =
count: 0,
});

const monitorTypeKeyLabelMap: Record<DataStream, string> = {
export const monitorTypeKeyLabelMap: Record<DataStream, string> = {
[DataStream.BROWSER]: 'Journey / Page',
[DataStream.HTTP]: 'HTTP',
[DataStream.TCP]: 'TCP',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { useDispatch, useSelector } from 'react-redux';
import { useKibana } from '@kbn/kibana-react-plugin/public';
import { useFetcher } from '@kbn/observability-plugin/public';

import { selectFiltersData, setListOfFiltersActions } from '../../../../state/overview_status';
import { ConfigKey } from '../../../../../../../common/runtime_types';
import { syntheticsMonitorType } from '../../../../../../../common/types/saved_objects';
import {
Expand All @@ -20,12 +21,11 @@ import {
} from '../../../../state';
import { SyntheticsUrlParams } from '../../../../utils/url_params';
import { useUrlParams } from '../../../../hooks';

import {
SyntheticsMonitorFilterField,
getMonitorFilterFields,
getSyntheticsFilterKeyForLabel,
SyntheticsMonitorFilterChangeHandler,
SyntheticsMonitorFilterField,
} from './filter_fields';

const aggs = {
Expand Down Expand Up @@ -84,10 +84,12 @@ interface AggsResponse {
};
}

export const useFilters = (): Record<
export type FiltersList = Record<
SyntheticsMonitorFilterField,
Array<{ label: string; count: number }>
> => {
>;

export const useFilters = (): FiltersList => {
const { savedObjects } = useKibana().services;

const { data } = useFetcher(async () => {
Expand All @@ -98,7 +100,11 @@ export const useFilters = (): Record<
});
}, []);

return useMemo(() => {
const filtersData = useSelector(selectFiltersData);

const dispatch = useDispatch();

const newFiltersData = useMemo(() => {
const { monitorTypes, tags, locations, projects, schedules } =
(data?.aggregations as AggsResponse) ?? {};
return {
Expand Down Expand Up @@ -131,10 +137,21 @@ export const useFilters = (): Record<
})) ?? [],
};
}, [data]);

useEffect(() => {
if (data) {
dispatch(setListOfFiltersActions(newFiltersData));
}
}, [data, dispatch, newFiltersData]);

if (!data && filtersData) {
return filtersData;
}

return newFiltersData;
};

type FilterFieldWithQuery = SyntheticsMonitorFilterField | 'query';
type FilterStateWithQuery = MonitorFilterState & { query?: string };

export function useMonitorFiltersState() {
const [getUrlParams, updateUrlParams] = useUrlParams();
Expand Down Expand Up @@ -163,7 +180,7 @@ export function useMonitorFiltersState() {
);

const serializeStateValues = useCallback(
(state: FilterStateWithQuery) => {
(state: MonitorFilterState) => {
return filterFieldsWithQuery.reduce(
(acc, cur) => ({
...acc,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ describe('useMonitorList', () => {
error: state.monitorList.error,
absoluteTotal: state.monitorList.data.absoluteTotal ?? 0,
pageState: state.monitorList.pageState,
isDataQueried: false,
syntheticsMonitors: selectEncryptedSyntheticsSavedMonitors.resultFunc(state.monitorList),
overviewStatus: null,
handleFilterChange: jest.fn(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,32 @@
* 2.0.
*/

import { useCallback, useRef, useEffect } from 'react';
import { useCallback, useEffect, useRef } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useDebounce } from 'react-use';
import { useOverviewStatus } from './use_overview_status';
import {
fetchMonitorListAction,
quietFetchMonitorListAction,
fetchOverviewStatusAction,
MonitorListPageState,
selectEncryptedSyntheticsSavedMonitors,
selectMonitorListState,
selectOverviewStatus,
updateManagementPageStateAction,
} from '../../../state';
import { useSyntheticsRefreshContext } from '../../../contexts';
import { useMonitorFiltersState } from '../common/monitor_filters/use_filters';

export function useMonitorList() {
const dispatch = useDispatch();
const isDataQueriedRef = useRef(false);
const isInitialMount = useRef(true);

const { pageState, loading, loaded, error, data } = useSelector(selectMonitorListState);
const syntheticsMonitors = useSelector(selectEncryptedSyntheticsSavedMonitors);
const { status: overviewStatus } = useSelector(selectOverviewStatus);

const { status: overviewStatus } = useOverviewStatus();

const { handleFilterChange } = useMonitorFiltersState();
const { refreshInterval } = useSyntheticsRefreshContext();
const { lastRefresh } = useSyntheticsRefreshContext();

const loadPage = useCallback(
(state: MonitorListPageState) => {
Expand All @@ -40,29 +40,39 @@ export function useMonitorList() {
);
const reloadPage = useCallback(() => loadPage(pageState), [pageState, loadPage]);

const reloadPageQuiet = useCallback(() => {
dispatch(quietFetchMonitorListAction(pageState));
}, [dispatch, pageState]);

// Periodically refresh
useEffect(() => {
const intervalId = setInterval(() => {
reloadPageQuiet();
}, refreshInterval);
if (!isInitialMount.current) {
dispatch(quietFetchMonitorListAction(pageState));
}
// specifically only want to run this on refreshInterval change
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [lastRefresh]);

return () => {
clearInterval(intervalId);
};
}, [reloadPageQuiet, refreshInterval]);
// On initial mount, load the page
useEffect(() => {
if (isInitialMount.current) {
if (loaded) {
dispatch(quietFetchMonitorListAction(pageState));
} else {
dispatch(fetchMonitorListAction.get(pageState));
}
}
// we don't use pageState here, for pageState, useDebounce will handle it
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [dispatch]);

useDebounce(
() => {
const overviewStatusArgs = { ...pageState, perPage: pageState.pageSize };

dispatch(fetchOverviewStatusAction.get(overviewStatusArgs));
// Don't load on initial mount, only meant to handle pageState changes
if (isInitialMount.current || !loaded) {
// setting false here to account for debounce timing
isInitialMount.current = false;
return;
}
dispatch(fetchMonitorListAction.get(pageState));
},
500,
200,
[pageState]
);

Expand All @@ -75,7 +85,6 @@ export function useMonitorList() {
total: data?.total ?? 0,
loadPage,
reloadPage,
isDataQueried: isDataQueriedRef.current,
absoluteTotal: data.absoluteTotal ?? 0,
overviewStatus,
handleFilterChange,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,39 +5,39 @@
* 2.0.
*/

import { useEffect, useRef, useCallback } from 'react';
import { useEffect, useCallback } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useSyntheticsRefreshContext } from '../../../contexts/synthetics_refresh_context';
import { selectOverviewPageState } from '../../../state';
import {
fetchOverviewStatusAction,
quietFetchOverviewStatusAction,
MonitorOverviewPageState,
selectOverviewStatus,
} from '../../../state';
} from '../../../state/overview_status';

export function useOverviewStatus({ pageState }: { pageState: MonitorOverviewPageState }) {
const { status, statusError } = useSelector(selectOverviewStatus);
export function useOverviewStatus() {
const pageState = useSelector(selectOverviewPageState);

const { status, error, loaded } = useSelector(selectOverviewStatus);

const { lastRefresh } = useSyntheticsRefreshContext();
const lastRefreshRef = useRef(lastRefresh);

const dispatch = useDispatch();
const reload = useCallback(() => {
dispatch(fetchOverviewStatusAction.get(pageState));
}, [dispatch, pageState]);

useEffect(() => {
if (lastRefresh !== lastRefreshRef.current) {
if (loaded) {
dispatch(quietFetchOverviewStatusAction.get(pageState));
lastRefreshRef.current = lastRefresh;
} else {
reload();
}
}, [dispatch, reload, lastRefresh, pageState]);
}, [dispatch, reload, lastRefresh, pageState, loaded]);

return {
status,
statusError,
error,
reload,
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
useEuiTheme,
EuiText,
EuiFlexItem,
EuiLoadingContent,
} from '@elastic/eui';
import { euiStyled } from '@kbn/kibana-react-plugin/common';

Expand Down Expand Up @@ -102,13 +101,8 @@ const MonitorStat = ({
return (
<EuiStatStyled
description={description}
title={
!isNaN(statValue) ? (
<EuiI18nNumber css={{ fontSize: euiTheme.size.m }} value={statValue} />
) : (
<EuiLoadingContent lines={2} />
)
}
isLoading={isNaN(statValue)}
title={<EuiI18nNumber css={{ fontSize: euiTheme.size.m }} value={statValue} />}
reverse={true}
/>
);
Expand Down
Loading

0 comments on commit 7288b84

Please sign in to comment.