[Synthetics] use_monitor_name - remove public saved object client usage (#158021)

Co-authored-by: shahzad31 <shahzad31comp@gmail.com>
This commit is contained in:
Dominique Clarke 2023-05-24 06:51:52 -04:00 committed by GitHub
parent 504d2216b2
commit dc20c71811
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 178 additions and 196 deletions

View file

@ -60,7 +60,7 @@ import {
ThrottlingWrapper,
} from './field_wrappers';
import { getDocLinks } from '../../../../../kibana_services';
import { useMonitorName } from '../hooks/use_monitor_name';
import { useMonitorName } from '../../../hooks/use_monitor_name';
import {
ConfigKey,
DataStream,

View file

@ -1,80 +0,0 @@
/*
* 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 { defaultCore, WrappedHelper } from '../../../utils/testing/rtl_helpers';
import { renderHook } from '@testing-library/react-hooks';
import { useMonitorName } from './use_monitor_name';
import { Router, useParams } from 'react-router-dom';
const mockRouter = {
useParams,
...Router,
};
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useParams: jest.fn().mockReturnValue({}),
}));
describe('useMonitorName', () => {
it('returns expected results', () => {
const { result } = renderHook(() => useMonitorName({}), { wrapper: WrappedHelper });
expect(result.current).toStrictEqual({ nameAlreadyExists: false, validName: '' });
expect(defaultCore.savedObjects.client.find).toHaveBeenCalledWith({
aggs: {
monitorNames: {
terms: { field: 'synthetics-monitor.attributes.name.keyword', size: 10000 },
},
},
perPage: 0,
type: 'synthetics-monitor',
});
});
it('returns expected results after data', async () => {
defaultCore.savedObjects.client.find = jest.fn().mockReturnValue({
aggregations: {
monitorNames: {
buckets: [{ key: 'Test' }, { key: 'Test 1' }],
},
},
});
const { result, waitForNextUpdate } = renderHook(() => useMonitorName({ search: 'Test' }), {
wrapper: WrappedHelper,
});
expect(result.current).toStrictEqual({ nameAlreadyExists: false, validName: 'Test' });
await waitForNextUpdate();
expect(result.current).toStrictEqual({ nameAlreadyExists: true, validName: '' });
});
it('returns expected results after data while editing monitor', async () => {
defaultCore.savedObjects.client.find = jest.fn().mockReturnValue({
aggregations: {
monitorNames: {
buckets: [{ key: 'Test' }, { key: 'Test 1' }],
},
},
});
jest.spyOn(mockRouter, 'useParams').mockReturnValue({ monitorId: 'test-id' });
const { result, waitForNextUpdate } = renderHook(() => useMonitorName({ search: 'Test' }), {
wrapper: WrappedHelper,
});
expect(result.current).toStrictEqual({ nameAlreadyExists: false, validName: 'Test' });
await waitForNextUpdate();
expect(result.current).toStrictEqual({ nameAlreadyExists: false, validName: 'Test' });
});
});

View file

@ -1,64 +0,0 @@
/*
* 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 { useEffect, useState } from 'react';
import { useFetcher } from '@kbn/observability-shared-plugin/public';
import { useKibana } from '@kbn/kibana-react-plugin/public';
import { useParams } from 'react-router-dom';
import { syntheticsMonitorType } from '../../../../../../common/types/saved_objects';
interface AggsResponse {
monitorNames: {
buckets: Array<{
key: string;
}>;
};
}
export const useMonitorName = ({ search = '' }: { search?: string }) => {
const [values, setValues] = useState<string[]>([]);
const { monitorId } = useParams<{ monitorId: string }>();
const { savedObjects } = useKibana().services;
const { data } = useFetcher(() => {
const aggs = {
monitorNames: {
terms: {
field: `${syntheticsMonitorType}.attributes.name.keyword`,
size: 10000,
},
},
};
return savedObjects?.client.find<unknown, typeof aggs>({
type: syntheticsMonitorType,
perPage: 0,
aggs,
});
}, []);
useEffect(() => {
if (data?.aggregations) {
const newValues = (data.aggregations as AggsResponse)?.monitorNames.buckets.map(({ key }) =>
key.toLowerCase()
);
if (monitorId && newValues.includes(search.toLowerCase())) {
setValues(newValues.filter((val) => val !== search.toLowerCase()));
} else {
setValues(newValues);
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [data, monitorId]);
const hasMonitor = Boolean(
search && values && values.length > 0 && values?.includes(search.trim().toLowerCase())
);
return { nameAlreadyExists: hasMonitor, validName: hasMonitor ? '' : search };
};

View file

@ -17,8 +17,8 @@ import {
import { i18n } from '@kbn/i18n';
import { useHistory } from 'react-router-dom';
import { useRecentlyViewedMonitors } from './use_recently_viewed_monitors';
import { useMonitorName } from '../../../hooks/use_monitor_name';
import { useSelectedLocation } from '../hooks/use_selected_location';
import { useMonitorName } from './use_monitor_name';
import { AddMonitorLink } from '../../common/links/add_monitor';
import { useSyntheticsSettingsContext } from '../../../contexts';

View file

@ -1,36 +0,0 @@
/*
* 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 { useMemo } from 'react';
import { useFetcher } from '@kbn/observability-shared-plugin/public';
import { useParams } from 'react-router-dom';
import { fetchMonitorManagementList } from '../../../state';
export const useMonitorName = ({ search = '' }: { search?: string }) => {
const { data, loading } = useFetcher(() => {
return fetchMonitorManagementList({
pageSize: 100,
pageIndex: 0,
sortField: 'name.keyword',
sortOrder: 'asc',
query: search,
});
}, [search]);
const { monitorId } = useParams<{ monitorId: string }>();
return useMemo(() => {
const { monitors = [] } = data ?? {};
const values = monitors.map((monitor) => ({
label: monitor.attributes.name as string,
key: monitor.id,
locationIds: monitor.attributes.locations.map((location) => location.id),
}));
return { values: values.filter((val) => val.key !== monitorId), loading };
}, [data, loading, monitorId]);
};

View file

@ -11,7 +11,7 @@ import {
getSyntheticsFilterDisplayValues,
SyntheticsMonitorFilterItem,
valueToLabelWithEmptyCount,
} from './filter_fields';
} from '../../../../utils/filters/filter_fields';
import { useGetUrlParams } from '../../../../hooks';
import { useMonitorFiltersState } from './use_filters';

View file

@ -17,7 +17,7 @@ import {
getSyntheticsFilterDisplayValues,
SyntheticsMonitorFilterChangeHandler,
LabelWithCountValue,
} from './filter_fields';
} from '../../../../utils/filters/filter_fields';
import { useFilters } from './use_filters';
import { FilterButton } from './filter_button';

View file

@ -10,7 +10,7 @@ import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { FilterGroup } from './filter_group';
import { SearchField } from '../search_field';
import { SyntheticsMonitorFilterChangeHandler } from './filter_fields';
import { SyntheticsMonitorFilterChangeHandler } from '../../../../utils/filters/filter_fields';
export const ListFilters = function ({
handleFilterChange,

View file

@ -25,7 +25,7 @@ import {
getSyntheticsFilterKeyForLabel,
SyntheticsMonitorFilterChangeHandler,
SyntheticsMonitorFilterField,
} from './filter_fields';
} from '../../../../utils/filters/filter_fields';
export const useFilters = (): MonitorFiltersResult | null => {
const dispatch = useDispatch();

View file

@ -8,6 +8,7 @@
import { useCallback, useEffect, useRef } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useDebounce } from 'react-use';
import { useMonitorFiltersState } from '../common/monitor_filters/use_filters';
import {
fetchMonitorListAction,
quietFetchMonitorListAction,
@ -17,9 +18,8 @@ import {
updateManagementPageStateAction,
} from '../../../state';
import { useSyntheticsRefreshContext } from '../../../contexts';
import { useMonitorFiltersState } from '../common/monitor_filters/use_filters';
export function useMonitorList() {
export function useMonitorList(query?: string) {
const dispatch = useDispatch();
const isInitialMount = useRef(true);
@ -40,11 +40,11 @@ export function useMonitorList() {
// Periodically refresh
useEffect(() => {
if (!isInitialMount.current) {
dispatch(quietFetchMonitorListAction(pageState));
dispatch(quietFetchMonitorListAction({ ...pageState, query }));
}
// specifically only want to run this on refreshInterval change
// specifically only want to run this on refreshInterval change on query change
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [lastRefresh]);
}, [lastRefresh, query]);
// On initial mount, load the page
useDebounce(

View file

@ -10,11 +10,11 @@ import { EuiSpacer } from '@elastic/eui';
import { useSelector } from 'react-redux';
import type { useMonitorList } from '../hooks/use_monitor_list';
import { selectOverviewStatus } from '../../../state/overview_status';
import { MonitorAsyncError } from './monitor_errors/monitor_async_error';
import { ListFilters } from '../common/monitor_filters/list_filters';
import { MonitorList } from './monitor_list_table/monitor_list';
import { MonitorStats } from './monitor_stats/monitor_stats';
import { selectOverviewStatus } from '../../../state/overview_status';
import { AlertingCallout } from '../../common/alerting_callout/alerting_callout';
export const MonitorListContainer = ({

View file

@ -14,7 +14,7 @@ import { OverviewLoader } from '../overview_loader';
import {
getSyntheticsFilterDisplayValues,
monitorTypeKeyLabelMap,
} from '../../../common/monitor_filters/filter_fields';
} from '../../../../../utils/filters/filter_fields';
import { useFilters } from '../../../common/monitor_filters/use_filters';
import { GroupGridItem } from './grid_group_item';
import { ConfigKey, MonitorOverviewItem } from '../../../../../../../../common/runtime_types';

View file

@ -0,0 +1,126 @@
/*
* 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 { WrappedHelper } from '../utils/testing/rtl_helpers';
import { renderHook } from '@testing-library/react-hooks';
import { useMonitorName } from './use_monitor_name';
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useParams: jest.fn().mockReturnValue({ monitorId: '12345' }),
}));
describe('useMonitorName', () => {
const Wrapper = ({ children }: { children: React.ReactElement }) => {
return (
<WrappedHelper
state={{
monitorList: {
error: null,
loading: true,
loaded: false,
monitorUpsertStatuses: {},
data: {
absoluteTotal: 1,
perPage: 5,
page: 1,
total: 1,
monitors: [
{
attributes: {
name: 'Test monitor name',
config_id: '12345',
locations: [
{
id: 'us_central_qa',
},
],
},
},
{
attributes: {
name: 'Test monitor name 2',
config_id: '12346',
locations: [
{
id: 'us_central_qa',
},
],
},
},
],
syncErrors: [],
},
pageState: {
pageIndex: 1,
pageSize: 10,
sortOrder: 'asc',
sortField: `name.keyword`,
},
},
}}
>
{children}
</WrappedHelper>
);
};
it('returns expected results', () => {
const { result } = renderHook(() => useMonitorName({}), { wrapper: Wrapper });
expect(result.current).toStrictEqual({
loading: true,
values: [
{
key: '12346',
label: 'Test monitor name 2',
locationIds: ['us_central_qa'],
},
],
nameAlreadyExists: false,
validName: '',
});
});
it('returns expected results after data', async () => {
const { result } = renderHook(() => useMonitorName({ search: 'Test monitor name 2' }), {
wrapper: Wrapper,
});
expect(result.current).toStrictEqual({
loading: true,
nameAlreadyExists: false,
validName: 'Test monitor name 2',
values: [
{
key: '12346',
label: 'Test monitor name 2',
locationIds: ['us_central_qa'],
},
],
});
});
it('returns expected results after data while editing monitor', async () => {
const { result } = renderHook(() => useMonitorName({ search: 'Test monitor name' }), {
wrapper: Wrapper,
});
expect(result.current).toStrictEqual({
loading: true,
nameAlreadyExists: false,
validName: 'Test monitor name',
values: [
{
key: '12346',
label: 'Test monitor name 2',
locationIds: ['us_central_qa'],
},
],
});
});
});

View file

@ -0,0 +1,36 @@
/*
* 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 { useMemo } from 'react';
import { useParams } from 'react-router-dom';
import { useMonitorList } from '../components/monitors_page/hooks/use_monitor_list';
export const useMonitorName = ({ search = '' }: { search?: string }) => {
const { monitorId } = useParams<{ monitorId: string }>();
const { syntheticsMonitors, loading } = useMonitorList(search);
return useMemo(() => {
const nameAlreadyExists = Boolean(
syntheticsMonitors?.some(
(monitor) => monitor.name.trim().toLowerCase() === search && monitorId !== monitor.config_id
)
);
const values = syntheticsMonitors.map((monitor) => ({
label: monitor.name as string,
key: monitor.config_id,
locationIds: monitor.locations.map((location) => location.id),
}));
return {
loading,
nameAlreadyExists,
validName: nameAlreadyExists ? '' : search,
values: values.filter((val) => val.key !== monitorId),
};
}, [loading, monitorId, syntheticsMonitors, search]);
};

View file

@ -7,8 +7,8 @@
import { i18n } from '@kbn/i18n';
import { invert } from 'lodash';
import { DataStream, ServiceLocations } from '../../../../../../../common/runtime_types';
import { MonitorFilterState } from '../../../../state';
import { DataStream, ServiceLocations } from '../../../../../common/runtime_types';
import { MonitorFilterState } from '../../state';
export type SyntheticsMonitorFilterField = keyof Omit<MonitorFilterState, 'query'>;

View file

@ -21,7 +21,7 @@ export default function ({ getService }: FtrProviderContext) {
await kibanaServer.savedObjects.clean({ types: [syntheticsMonitorType] });
});
beforeEach(async () => {
before(async () => {
await kibanaServer.savedObjects.clean({ types: [syntheticsMonitorType] });
});