Skip to content

Commit

Permalink
[Uptime] Create new atomic params type for status alerts (#67720)
Browse files Browse the repository at this point in the history
* Create new atomic params type for status alerts.

* Update executor params typing to support both alert params types.

* Update snapshot for alert factory function.

* Fix broken types and refresh snapshots.

* Clean up naming of action/selector.

* Fix a bug and add tests.

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
  • Loading branch information
justinkambic and elasticmachine authored Jun 3, 2020
1 parent 884704d commit 6f3e1bf
Show file tree
Hide file tree
Showing 29 changed files with 474 additions and 155 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,32 @@ describe('stringifyKueries', () => {
kueries.set('monitor.id', ['https://elastic.co', 'https://example.com']);
expect(stringifyKueries(kueries)).toMatchSnapshot();
});

it('handles precending empty array', () => {
kueries = new Map<string, string[]>(
Object.entries({
'monitor.type': [],
'observer.geo.name': ['us-east', 'apj', 'sydney', 'us-west'],
tags: [],
'url.port': [],
})
);
expect(stringifyKueries(kueries)).toMatchInlineSnapshot(
`"(observer.geo.name:us-east or observer.geo.name:apj or observer.geo.name:sydney or observer.geo.name:us-west)"`
);
});

it('handles skipped empty arrays', () => {
kueries = new Map<string, string[]>(
Object.entries({
tags: [],
'monitor.type': ['http'],
'url.port': [],
'observer.geo.name': ['us-east', 'apj', 'sydney', 'us-west'],
})
);
expect(stringifyKueries(kueries)).toMatchInlineSnapshot(
`"monitor.type:http and (observer.geo.name:us-east or observer.geo.name:apj or observer.geo.name:sydney or observer.geo.name:us-west)"`
);
});
});
8 changes: 8 additions & 0 deletions x-pack/plugins/uptime/common/lib/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

export * from './combine_filters_and_user_search';
export * from './stringify_kueries';
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ export const stringifyKueries = (kueries: Map<string, Array<number | string>>):
.reduce((prev, cur, index, array) => {
if (array.length === 1 || index === 0) {
return cur;
} else if (cur === '') {
return prev;
} else if (prev === '' && !!cur) {
return cur;
}
return `${prev} and ${cur}`;
}, '');
27 changes: 25 additions & 2 deletions x-pack/plugins/uptime/common/runtime_types/alerts/status_check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,30 @@

import * as t from 'io-ts';

export const StatusCheckExecutorParamsType = t.intersection([
export const StatusCheckFiltersType = t.type({
'monitor.type': t.array(t.string),
'observer.geo.name': t.array(t.string),
tags: t.array(t.string),
'url.port': t.array(t.string),
});

export type StatusCheckFilters = t.TypeOf<typeof StatusCheckFiltersType>;

export const AtomicStatusCheckParamsType = t.intersection([
t.type({
numTimes: t.number,
timerangeCount: t.number,
timerangeUnit: t.string,
}),
t.partial({
search: t.string,
filters: StatusCheckFiltersType,
}),
]);

export type AtomicStatusCheckParams = t.TypeOf<typeof AtomicStatusCheckParamsType>;

export const StatusCheckParamsType = t.intersection([
t.partial({
filters: t.string,
}),
Expand All @@ -20,4 +43,4 @@ export const StatusCheckExecutorParamsType = t.intersection([
}),
]);

export type StatusCheckExecutorParams = t.TypeOf<typeof StatusCheckExecutorParamsType>;
export type StatusCheckParams = t.TypeOf<typeof StatusCheckParamsType>;
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

import React, { useEffect, useState } from 'react';
import React, { useState } from 'react';
import { EuiSpacer } from '@elastic/eui';
import { DataPublicPluginSetup } from 'src/plugins/data/public';
import * as labels from './translations';
Expand Down Expand Up @@ -35,10 +35,6 @@ export const AlertMonitorStatusComponent: React.FC<AlertMonitorStatusProps> = (p

const [newFilters, setNewFilters] = useState<string[]>([]);

useEffect(() => {
setAlertParams('filters', filters);
}, [filters, setAlertParams]);

return (
<>
<EuiSpacer size="m" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
* you may not use this file except in compliance with the Elastic License.
*/

import React from 'react';
import React, { useEffect } from 'react';
import { useSelector } from 'react-redux';
import { DataPublicPluginSetup } from 'src/plugins/data/public';
import { selectMonitorStatusAlert } from '../../../../state/selectors';
import { selectMonitorStatusAlert, searchTextSelector } from '../../../../state/selectors';
import { AlertMonitorStatusComponent } from '../index';

interface Props {
Expand All @@ -29,6 +29,12 @@ export const AlertMonitorStatus: React.FC<Props> = ({
timerange,
}) => {
const { filters, locations } = useSelector(selectMonitorStatusAlert);
const searchText = useSelector(searchTextSelector);

useEffect(() => {
setAlertParams('search', searchText);
}, [setAlertParams, searchText]);

return (
<AlertMonitorStatusComponent
autocomplete={autocomplete}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { overviewFiltersSelector } from '../../../../state/selectors';
import { useFilterUpdate } from '../../../../hooks/use_filter_update';
import { filterLabels } from '../../filter_group/translations';
import { alertFilterLabels } from './translations';
import { StatusCheckFilters } from '../../../../../common/runtime_types';

interface Props {
newFilters: string[];
Expand All @@ -38,19 +39,22 @@ export const FiltersExpressionsSelect: React.FC<Props> = ({
updatedFieldValues.values
);

useEffect(() => {
if (updatedFieldValues.fieldName === 'observer.geo.name') {
setAlertParams('locations', updatedFieldValues.values);
}
}, [setAlertParams, updatedFieldValues]);
const [filters, setFilters] = useState<StatusCheckFilters>({
'observer.geo.name': selectedLocations,
'url.port': selectedPorts,
tags: selectedTags,
'monitor.type': selectedSchemes,
});

useEffect(() => {
setAlertParams('locations', []);

// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
setAlertParams('filters', filters);
}, [filters, setAlertParams]);

const onFilterFieldChange = (fieldName: string, values: string[]) => {
setFilters({
...filters,
[fieldName]: values,
});
setUpdatedFieldValues({ fieldName, values });
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ export const TimeExpressionSelect: React.FC<Props> = ({ setAlertParams }) => {

useEffect(() => {
const timerangeUnit = timerangeUnitOptions.find(({ checked }) => checked === 'on')?.key ?? 'm';
setAlertParams('timerange', { from: `now-${numUnits}${timerangeUnit}`, to: 'now' });
setAlertParams('timerangeUnit', timerangeUnit);
setAlertParams('timerangeCount', numUnits);
}, [numUnits, timerangeUnitOptions, setAlertParams]);

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@
* you may not use this file except in compliance with the Elastic License.
*/

import React, { useState } from 'react';
import React, { useState, useEffect } from 'react';
import { uniqueId, startsWith } from 'lodash';
import { EuiCallOut } from '@elastic/eui';
import styled from 'styled-components';
import { FormattedMessage } from '@kbn/i18n/react';
import { Typeahead } from './typeahead';
import { useUrlParams } from '../../../hooks';
import { useSearchText, useUrlParams } from '../../../hooks';
import {
esKuery,
IIndexPattern,
Expand Down Expand Up @@ -45,6 +45,7 @@ export function KueryBar({
'data-test-subj': dataTestSubj,
}: Props) {
const { loading, index_pattern: indexPattern } = useIndexPattern();
const { updateSearchText } = useSearchText();

const [state, setState] = useState<State>({
suggestions: [],
Expand All @@ -56,13 +57,19 @@ export function KueryBar({
const [getUrlParams, updateUrlParams] = useUrlParams();
const { search: kuery } = getUrlParams();

useEffect(() => {
updateSearchText(kuery);
}, [kuery, updateSearchText]);

const indexPatternMissing = loading && !indexPattern;

async function onChange(inputValue: string, selectionStart: number) {
if (!indexPattern) {
return;
}

updateSearchText(inputValue);

setIsLoadingSuggestions(true);
setState({ ...state, suggestions: [] });

Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/uptime/public/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ export * from './use_url_params';
export * from './use_telemetry';
export * from './update_kuery_string';
export * from './use_cert_status';
export * from './use_search_text';
2 changes: 1 addition & 1 deletion x-pack/plugins/uptime/public/hooks/update_kuery_string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { combineFiltersAndUserSearch, stringifyKueries } from '../lib/helper';
import { esKuery, IIndexPattern } from '../../../../../src/plugins/data/public';
import { combineFiltersAndUserSearch, stringifyKueries } from '../../common/lib';

const getKueryString = (urlFilters: string): string => {
let kueryString = '';
Expand Down
22 changes: 22 additions & 0 deletions x-pack/plugins/uptime/public/hooks/use_search_text.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { useCallback } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { setSearchTextAction } from '../state/actions';
import { searchTextSelector } from '../state/selectors';

export const useSearchText = () => {
const dispatch = useDispatch();
const searchText = useSelector(searchTextSelector);

const updateSearchText = useCallback(
(nextSearchText: string) => dispatch(setSearchTextAction(nextSearchText)),
[dispatch]
);

return { searchText, updateSearchText };
};
Loading

0 comments on commit 6f3e1bf

Please sign in to comment.