From 68c6e13fdfb36dd3a4ed7dfd4de090e4b40c34e9 Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Fri, 5 Jun 2020 16:10:38 -0400 Subject: [PATCH] Add new state for selected filters. --- .../overview/alerts/add_filter_btn.tsx | 8 ++--- .../overview/alerts/alert_monitor_status.tsx | 29 +++++++-------- .../alert_monitor_status.tsx | 17 +++++++++ .../uptime/public/hooks/use_url_params.ts | 36 +++++++++++++++++++ .../public/state/actions/selected_filters.ts | 21 +++++++++++ .../uptime/public/state/reducers/index.ts | 2 ++ .../public/state/reducers/selected_filters.ts | 32 +++++++++++++++++ .../uptime/public/state/selectors/index.ts | 2 ++ 8 files changed, 126 insertions(+), 21 deletions(-) create mode 100644 x-pack/plugins/uptime/public/state/actions/selected_filters.ts create mode 100644 x-pack/plugins/uptime/public/state/reducers/selected_filters.ts diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/add_filter_btn.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/add_filter_btn.tsx index f633727a0af3..d9011c896ffd 100644 --- a/x-pack/plugins/uptime/public/components/overview/alerts/add_filter_btn.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/add_filter_btn.tsx @@ -6,20 +6,18 @@ import React, { useState } from 'react'; import { EuiButtonEmpty, EuiContextMenuItem, EuiContextMenuPanel, EuiPopover } from '@elastic/eui'; -import { useFilterUpdate } from '../../../hooks/use_filter_update'; import * as labels from './translations'; interface Props { newFilters: string[]; onNewFilter: (val: string) => void; + alertFilters: { [key: string]: string[] }; } -export const AddFilterButton: React.FC = ({ newFilters, onNewFilter }) => { +export const AddFilterButton: React.FC = ({ newFilters, onNewFilter, alertFilters }) => { const [isPopoverOpen, setPopover] = useState(false); - const { selectedFilters } = useFilterUpdate(); - - const getSelectedItems = (fieldName: string) => selectedFilters.get(fieldName) || []; + const getSelectedItems = (fieldName: string) => alertFilters?.[fieldName] ?? []; const onButtonClick = () => { setPopover(!isPopoverOpen); diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx index fdaa18c36d60..cd055d4cb72d 100644 --- a/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx @@ -5,7 +5,7 @@ */ import React, { useState } from 'react'; -import { EuiCallOut, EuiLoadingSpinner, EuiSpacer } from '@elastic/eui'; +import { EuiCallOut, EuiSpacer } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { DataPublicPluginSetup } from 'src/plugins/data/public'; import * as labels from './translations'; @@ -110,6 +110,7 @@ export const AlertMonitorStatusComponent: React.FC = (p { setNewFilters([...newFilters, newFilter]); @@ -118,21 +119,17 @@ export const AlertMonitorStatusComponent: React.FC = (p - {!snapshotLoading ? ( - - } - iconType="iInCircle" - /> - ) : ( - - )} + + } + iconType="iInCircle" + /> diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx index d665c98c434e..b570572ba79d 100644 --- a/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx @@ -13,6 +13,7 @@ import { overviewFiltersSelector, snapshotDataSelector, esKuerySelector, + selectedFiltersSelector, } from '../../../../state/selectors'; import { AlertMonitorStatusComponent } from '../index'; import { @@ -92,6 +93,22 @@ export const AlertMonitorStatus: React.FC = ({ ); }, [dispatch, esKuery]); + const selectedFilters = useSelector(selectedFiltersSelector); + useEffect(() => { + if (!alertParams.filters && selectedFilters !== null) { + setAlertParams('filters', { + // @ts-ignore + 'url.port': selectedFilters?.ports ?? [], + // @ts-ignore + 'observer.geo.name': selectedFilters?.locations ?? [], + // @ts-ignore + 'monitor.type': selectedFilters?.schemes ?? [], + // @ts-ignore + tags: selectedFilters?.tags ?? [], + }); + } + }, [alertParams, setAlertParams, selectedFilters]); + return ( UptimeUrlParams; export type UpdateUrlParams = (updatedParams: { @@ -27,9 +31,35 @@ export const useGetUrlParams: GetUrlParams = () => { return getSupportedUrlParams(params); }; +const getMapFromFilters = (value: any): Map | undefined => { + try { + return new Map(JSON.parse(value)); + } catch { + return undefined; + } +}; + +const mapMapToObject = (map: Map) => ({ + locations: map.get('observer.geo.name') ?? [], + ports: map.get('url.port') ?? [], + schemes: map.get('monitor.type') ?? [], + tags: map.get('tags') ?? [], +}); + export const useUrlParams: UptimeUrlParamsHook = () => { const location = useLocation(); const history = useHistory(); + const dispatch = useDispatch(); + const selectedFilters = useSelector(selectedFiltersSelector); + const { filters } = useGetUrlParams(); + useEffect(() => { + if (selectedFilters === null) { + const filterMap = getMapFromFilters(filters); + if (filterMap) { + dispatch(setSelectedFilters(mapMapToObject(filterMap))); + } + } + }, [dispatch, filters, selectedFilters]); const updateUrlParams: UpdateUrlParams = (updatedParams) => { if (!history || !location) return; @@ -57,6 +87,12 @@ export const useUrlParams: UptimeUrlParamsHook = () => { { sort: false } ), }); + const filterMap = getMapFromFilters(mergedParams.filters); + if (!filterMap) { + dispatch(setSelectedFilters(null)); + } else { + dispatch(setSelectedFilters(mapMapToObject(filterMap))); + } }; return [useGetUrlParams, updateUrlParams]; diff --git a/x-pack/plugins/uptime/public/state/actions/selected_filters.ts b/x-pack/plugins/uptime/public/state/actions/selected_filters.ts new file mode 100644 index 000000000000..11c159b09a15 --- /dev/null +++ b/x-pack/plugins/uptime/public/state/actions/selected_filters.ts @@ -0,0 +1,21 @@ +/* + * 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 { createAction } from 'redux-actions'; + +export interface SelectedFilters { + locations: string[]; + ports: number[]; + schemes: string[]; + tags: string[]; +} + +export type SelectedFiltersPayload = SelectedFilters; + +export const getSelectedFilters = createAction('GET SELECTED FILTERS'); +export const setSelectedFilters = createAction( + 'SET_SELECTED_FILTERS' +); diff --git a/x-pack/plugins/uptime/public/state/reducers/index.ts b/x-pack/plugins/uptime/public/state/reducers/index.ts index ead7f5b46431..c05c740ab8eb 100644 --- a/x-pack/plugins/uptime/public/state/reducers/index.ts +++ b/x-pack/plugins/uptime/public/state/reducers/index.ts @@ -19,6 +19,7 @@ import { monitorDurationReducer } from './monitor_duration'; import { indexStatusReducer } from './index_status'; import { mlJobsReducer } from './ml_anomaly'; import { certificatesReducer } from '../certificates/certificates'; +import { selectedFiltersReducer } from './selected_filters'; export const rootReducer = combineReducers({ monitor: monitorReducer, @@ -35,4 +36,5 @@ export const rootReducer = combineReducers({ monitorDuration: monitorDurationReducer, indexStatus: indexStatusReducer, certificates: certificatesReducer, + selectedFilters: selectedFiltersReducer, }); diff --git a/x-pack/plugins/uptime/public/state/reducers/selected_filters.ts b/x-pack/plugins/uptime/public/state/reducers/selected_filters.ts new file mode 100644 index 000000000000..108d516d17ab --- /dev/null +++ b/x-pack/plugins/uptime/public/state/reducers/selected_filters.ts @@ -0,0 +1,32 @@ +/* + * 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 { Action } from 'redux-actions'; +import { + getSelectedFilters, + setSelectedFilters, + SelectedFilters, +} from '../actions/selected_filters'; + +const initialState = null; + +export function selectedFiltersReducer( + state = initialState, + action: Action +): SelectedFilters | null { + switch (action.type) { + case String(getSelectedFilters): + return state; + case String(setSelectedFilters): + if (state === null) return { ...action.payload }; + return { + ...(state || {}), + ...action.payload, + }; + default: + return state; + } +} diff --git a/x-pack/plugins/uptime/public/state/selectors/index.ts b/x-pack/plugins/uptime/public/state/selectors/index.ts index b088c346ad81..d08db2ccf5f2 100644 --- a/x-pack/plugins/uptime/public/state/selectors/index.ts +++ b/x-pack/plugins/uptime/public/state/selectors/index.ts @@ -86,3 +86,5 @@ export const overviewFiltersSelector = ({ overviewFilters }: AppState) => overvi export const esKuerySelector = ({ ui: { esKuery } }: AppState) => esKuery; export const searchTextSelector = ({ ui: { searchText } }: AppState) => searchText; + +export const selectedFiltersSelector = ({ selectedFilters }: AppState) => selectedFilters;