From 0f2072f2923ee1fbf20e81930f58c29ca5237445 Mon Sep 17 00:00:00 2001 From: Sean Li Date: Tue, 22 Nov 2022 13:01:54 -0800 Subject: [PATCH 1/2] Implementing search feature Signed-off-by: Sean Li --- .../public/components/metrics/index.tsx | 6 +- .../metrics/redux/slices/metrics_slice.ts | 21 +++- .../metrics/sidebar/metric_name.tsx | 43 ++++++++ .../metrics/sidebar/metrics_accordion.tsx | 40 +++++++ .../components/metrics/sidebar/search_bar.tsx | 59 ++++------- .../components/metrics/sidebar/sidebar.scss | 8 +- .../components/metrics/sidebar/sidebar.tsx | 100 ++++-------------- .../components/metrics/top_menu/top_menu.tsx | 12 ++- 8 files changed, 163 insertions(+), 126 deletions(-) create mode 100644 dashboards-observability/public/components/metrics/sidebar/metric_name.tsx create mode 100644 dashboards-observability/public/components/metrics/sidebar/metrics_accordion.tsx diff --git a/dashboards-observability/public/components/metrics/index.tsx b/dashboards-observability/public/components/metrics/index.tsx index 9d1ae0722..0647cdaba 100644 --- a/dashboards-observability/public/components/metrics/index.tsx +++ b/dashboards-observability/public/components/metrics/index.tsx @@ -67,6 +67,7 @@ export const Home = ({ const resolutionSelectId = htmlIdGenerator('resolutionSelect')(); const [toasts, setToasts] = useState([]); const [toastRightSide, setToastRightSide] = useState(true); + const [search, setSearch] = useState(false); // Side bar constants const [isSidebarClosed, setIsSidebarClosed] = useState(false); @@ -170,13 +171,16 @@ export const Home = ({ resolutionSelectId={resolutionSelectId} savedObjects={savedObjects} setToast={setToast} + setSearch={setSearch} />
- {!isSidebarClosed && } + {!isSidebarClosed && ( + + )} id !== payload.id); }, + searchMetric: (state, { payload }) => { + state.searched = state.metrics.filter( + (metric: any) => metric.name.includes(payload.id) && !state.selected.includes(payload.id) + ); + }, + clearSearchedMetrics: (state, { payload }) => { + state.searched = []; + }, updateMetricsLayout: (state, { payload }) => { state.metricsLayout = payload; }, @@ -127,12 +136,19 @@ export const metricSlice = createSlice({ extraReducers: (builder) => { builder.addCase(loadMetrics.fulfilled, (state, { payload }) => { state.metrics = payload; + state.searched = []; filterDeletedLayoutIds(state, payload); }); }, }); -export const { deSelectMetric, selectMetric, updateMetricsLayout } = metricSlice.actions; +export const { + deSelectMetric, + selectMetric, + updateMetricsLayout, + searchMetric, + clearSearchedMetrics, +} = metricSlice.actions; export const metricsStateSelector = (state) => state.metrics; @@ -149,6 +165,9 @@ export const recentlyCreatedMetricsSelector = (state) => (metric) => !state.metrics.selected.includes(metric.id) && metric.recentlyCreated ); +export const searchedMetricsSelector = (state) => + state.metrics.searched.filter((metric) => !state.metrics.selected.includes(metric.id)); + export const allAvailableMetricsSelector = (state) => state.metrics.metrics.filter((metric) => !state.metrics.selected.includes(metric.id)); diff --git a/dashboards-observability/public/components/metrics/sidebar/metric_name.tsx b/dashboards-observability/public/components/metrics/sidebar/metric_name.tsx new file mode 100644 index 000000000..0998912bf --- /dev/null +++ b/dashboards-observability/public/components/metrics/sidebar/metric_name.tsx @@ -0,0 +1,43 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { EuiButtonEmpty, EuiToken } from '@elastic/eui'; + +interface IMetricNameProps { + metric: any; + handleClick: (props: any) => void; +} + +export const MetricName = (props: IMetricNameProps) => { + const { metric, handleClick } = props; + + const title = metric.catalog === 'CUSTOM_METRICS' ? 'OpenSearch' : 'Prometheus'; + const token = + metric.catalog === 'CUSTOM_METRICS' + ? '/ui/default_branding/opensearch_mark_default_mode.svg' + : 'tokenProperty'; + const name = (metricName: string) => { + return metric.catalog === 'CUSTOM_METRICS' ? metricName : metricName.split('.')[1]; + }; + + return ( + handleClick(metric)} + > + {' '} + {name(metric.name)} + + ); +}; diff --git a/dashboards-observability/public/components/metrics/sidebar/metrics_accordion.tsx b/dashboards-observability/public/components/metrics/sidebar/metrics_accordion.tsx new file mode 100644 index 000000000..71b42e674 --- /dev/null +++ b/dashboards-observability/public/components/metrics/sidebar/metrics_accordion.tsx @@ -0,0 +1,40 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { EuiAccordion, EuiTitle } from '@elastic/eui'; +import { MetricName } from './metric_name'; + +interface IMetricNameProps { + metricsList: []; + headerName: string; + handleClick: (props: any) => void; +} + +export const MetricsAccordion = (props: IMetricNameProps) => { + const { metricsList, headerName, handleClick } = props; + + return ( + + {headerName} + + } + paddingSize="none" + > +
    + {metricsList.slice(0, 100).map((metric: any) => ( +
  • + +
  • + ))} +
+ {metricsList.length > 100 &&

Use search bar for searching through all metrics.

} +
+ ); +}; diff --git a/dashboards-observability/public/components/metrics/sidebar/search_bar.tsx b/dashboards-observability/public/components/metrics/sidebar/search_bar.tsx index 9f3a7dafd..fc5656475 100644 --- a/dashboards-observability/public/components/metrics/sidebar/search_bar.tsx +++ b/dashboards-observability/public/components/metrics/sidebar/search_bar.tsx @@ -3,57 +3,40 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { EuiGlobalToastList, EuiSearchBar, EuiToast } from '@elastic/eui'; -import React, { useEffect, useState } from 'react'; -import { pplServiceRequestor } from '../helpers/utils'; +import { EuiSearchBar } from '@elastic/eui'; +import React from 'react'; +import { useDispatch } from 'react-redux'; +import { clearSearchedMetrics, searchMetric } from '../redux/slices/metrics_slice'; interface ISearchBarProps { - allAvailableMetrics: any; - handleAddMetric: any; + setSearch: React.Dispatch>; } export const SearchBar = (props: ISearchBarProps) => { - const { allAvailableMetrics, handleAddMetric } = props; + const { setSearch } = props; - const [query, setQuery] = useState(''); - const [error, setError] = useState(null); + const dispatch = useDispatch(); - const [toasts, setToasts] = useState([]); - const addToast = (res: string) => { - if (res === 'success') { - const toast = { - id: 'success', - title: 'Metric successfully added!!', - color: 'success', - }; - setToasts(toasts.concat(toast)); + const onChange = ({ query }: { query: any }) => { + if (query.text !== '') { + setSearch(true); + dispatch(searchMetric({ id: query.text })); } else { - const toast = { - id: 'fail', - title: 'Metric not found.', - color: 'danger', - }; - setToasts(toasts.concat(toast)); - } - }; - const removeToast = (removedToast: any) => { - setToasts(toasts.filter((toast: any) => toast.id !== removedToast.id)); - }; - - const onChange = ({ query }) => { - const metric = allAvailableMetrics.find((row: any) => row.name.includes(query.text)); - if (metric) { - handleAddMetric(metric); - addToast('success'); - } else { - addToast('fail'); + setSearch(false); + dispatch(clearSearchedMetrics({})); } }; return (
- - +
); }; diff --git a/dashboards-observability/public/components/metrics/sidebar/sidebar.scss b/dashboards-observability/public/components/metrics/sidebar/sidebar.scss index 069c5c86c..6be02c332 100644 --- a/dashboards-observability/public/components/metrics/sidebar/sidebar.scss +++ b/dashboards-observability/public/components/metrics/sidebar/sidebar.scss @@ -138,7 +138,6 @@ } .sidebarHeight { - // @include euiYScrollWithShadows; line-height:normal; overflow:auto; max-height:100vh; @@ -146,14 +145,13 @@ .metricsList { line-height:normal; - margin-top:5px; } .metricsListContainer { - margin-left:25px; + margin-left:15px; margin-right:5px; } -.metricName { - margin-bottom:10px; +.tokenMargin { + vertical-align:middle; } diff --git a/dashboards-observability/public/components/metrics/sidebar/sidebar.tsx b/dashboards-observability/public/components/metrics/sidebar/sidebar.tsx index f08665b79..c137dec3b 100644 --- a/dashboards-observability/public/components/metrics/sidebar/sidebar.tsx +++ b/dashboards-observability/public/components/metrics/sidebar/sidebar.tsx @@ -6,7 +6,7 @@ import './sidebar.scss'; import React, { useEffect } from 'react'; -import { EuiTitle, EuiSpacer, EuiAccordion, EuiLink } from '@elastic/eui'; +import { EuiSpacer } from '@elastic/eui'; import { I18nProvider } from '@osd/i18n/react'; import { batch, useDispatch, useSelector } from 'react-redux'; import { @@ -16,22 +16,26 @@ import { loadMetrics, selectedMetricsSelector, recentlyCreatedMetricsSelector, + searchedMetricsSelector, } from '../redux/slices/metrics_slice'; import { CoreStart } from '../../../../../../src/core/public'; import PPLService from '../../../services/requests/ppl'; +import { MetricsAccordion } from './metrics_accordion'; interface ISidebarProps { http: CoreStart['http']; pplService: PPLService; + search: boolean; } export const Sidebar = (props: ISidebarProps) => { - const { http, pplService } = props; + const { http, pplService, search } = props; const dispatch = useDispatch(); const availableMetrics = useSelector(availableMetricsSelector); const selectedMetrics = useSelector(selectedMetricsSelector); const recentlyCreatedMetrics = useSelector(recentlyCreatedMetricsSelector); + const searchedMetrics = useSelector(searchedMetricsSelector); useEffect(() => { batch(() => { @@ -45,86 +49,28 @@ export const Sidebar = (props: ISidebarProps) => { dispatch(deSelectMetric(metric)); }; + const availableMetricsDisplay = search ? searchedMetrics : availableMetrics; + return (
- - Recently Created Metrics - - } - paddingSize="none" - > -
    - {recentlyCreatedMetrics.map((metric: any) => ( -
  • - handleAddMetric(metric)} - > - {metric.name} - -
  • - ))} -
-
+ - - Selected Metrics - - } - paddingSize="none" - > -
    - {selectedMetrics.map((metric: any) => ( -
  • - handleRemoveMetric(metric)} - > - {metric.name} - -
  • - ))} -
-
+ - - Available Metrics - - } - paddingSize="none" - > -
    - {availableMetrics.slice(0, 100).map((metric: any) => ( -
  • - handleAddMetric(metric)} - > - {metric.name} - -
  • - ))} -
- {availableMetrics.length > 100 && ( -

Use search bar for searching through all metrics.

- )} -
+
); diff --git a/dashboards-observability/public/components/metrics/top_menu/top_menu.tsx b/dashboards-observability/public/components/metrics/top_menu/top_menu.tsx index c8adb9977..cd3d17e3b 100644 --- a/dashboards-observability/public/components/metrics/top_menu/top_menu.tsx +++ b/dashboards-observability/public/components/metrics/top_menu/top_menu.tsx @@ -1,3 +1,8 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + import { EuiPageHeader, EuiPageHeaderSection, @@ -52,6 +57,7 @@ interface TopMenuProps { resolutionSelectId: string; savedObjects: SavedObjects; setToast: (title: string, color?: string, text?: any, side?: string) => void; + setSearch: any; } export const TopMenu = ({ @@ -73,6 +79,7 @@ export const TopMenu = ({ resolutionSelectId, savedObjects, setToast, + setSearch, }: TopMenuProps) => { // Redux tools const dispatch = useDispatch(); @@ -209,10 +216,7 @@ export const TopMenu = ({ - + From c5028f804a7ee349b4191650364b66317f53f363 Mon Sep 17 00:00:00 2001 From: Sean Li Date: Tue, 22 Nov 2022 16:06:01 -0800 Subject: [PATCH 2/2] Updating tests Signed-off-by: Sean Li --- .../__snapshots__/searchbar.test.tsx.snap | 484 ++++++++--------- .../__snapshots__/sidebar.test.tsx.snap | 499 +++++++++--------- .../sidebar/__tests__/searchbar.test.tsx | 20 +- .../sidebar/__tests__/sidebar.test.tsx | 3 +- .../__snapshots__/top_menu.test.tsx.snap | 111 ++-- 5 files changed, 544 insertions(+), 573 deletions(-) diff --git a/dashboards-observability/public/components/metrics/sidebar/__tests__/__snapshots__/searchbar.test.tsx.snap b/dashboards-observability/public/components/metrics/sidebar/__tests__/__snapshots__/searchbar.test.tsx.snap index 0dd14e663..1a271b63c 100644 --- a/dashboards-observability/public/components/metrics/sidebar/__tests__/__snapshots__/searchbar.test.tsx.snap +++ b/dashboards-observability/public/components/metrics/sidebar/__tests__/__snapshots__/searchbar.test.tsx.snap @@ -1,323 +1,295 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Search Bar Component Search Side Bar Component with available metrics 1`] = ` - -
- - +
+ -
- -
- - - -
- - - - -
- + + +
- - - - -
-
+ + + + + + +
+
+
+
-
- - - -
- -
-
-
- -
- -
- + + + +
+ +
+ + +
+ + `; exports[`Search Bar Component Search Side Bar Component with no available metrics 1`] = ` - -
- - +
+ -
- -
- - - -
- - - - -
- + + +
- - - - -
-
+ > + + + + +
+
+
+
-
- - - -
- -
-
-
- -
- -
- + + + +
+ +
+ + + + + `; diff --git a/dashboards-observability/public/components/metrics/sidebar/__tests__/__snapshots__/sidebar.test.tsx.snap b/dashboards-observability/public/components/metrics/sidebar/__tests__/__snapshots__/sidebar.test.tsx.snap index b7f4adfcd..b4ba2e2b7 100644 --- a/dashboards-observability/public/components/metrics/sidebar/__tests__/__snapshots__/sidebar.test.tsx.snap +++ b/dashboards-observability/public/components/metrics/sidebar/__tests__/__snapshots__/sidebar.test.tsx.snap @@ -20,6 +20,7 @@ exports[`Side Bar Component renders Side Bar Component 1`] = ` "http": [MockFunction], } } + search={false} > - - - Recently Created Metrics - - - } - id="recentlyCreatedMetricsSelector" - initialIsOpen={true} - isLoading={false} - isLoadingMessage={false} - paddingSize="none" + -
+ + Recently Created Metrics + + + } + id="Recently Created MetricsSelector" + initialIsOpen={true} + isLoading={false} + isLoadingMessage={false} + paddingSize="none" >
- -
-
- + Recently Created Metrics + + + + +
+
-
-
-
    + +
    +
    +
      +
    -
- + +
-
-
+ + @@ -215,104 +222,110 @@ exports[`Side Bar Component renders Side Bar Component 1`] = ` className="euiSpacer euiSpacer--s" /> - - - Selected Metrics - - - } - id="selectedMetricsSelector" - initialIsOpen={true} - isLoading={false} - isLoadingMessage={false} - paddingSize="none" + -
+ + Selected Metrics + + + } + id="Selected MetricsSelector" + initialIsOpen={true} + isLoading={false} + isLoadingMessage={false} + paddingSize="none" >
- -
-
- + Selected Metrics + + + + +
+
-
-
-
    + +
    +
    +
      +
    -
- + +
-
-
+ + @@ -320,104 +333,110 @@ exports[`Side Bar Component renders Side Bar Component 1`] = ` className="euiSpacer euiSpacer--s" /> - - - Available Metrics - - - } - id="availableMetricsSelector" - initialIsOpen={true} - isLoading={false} - isLoadingMessage={false} - paddingSize="none" + -
+ + Available Metrics + + + } + id="Available MetricsSelector" + initialIsOpen={true} + isLoading={false} + isLoadingMessage={false} + paddingSize="none" >
- -
-
- + Available Metrics + + + + +
+
-
-
-
    + +
    +
    +
      +
    -
- + +
-
-
+ +
diff --git a/dashboards-observability/public/components/metrics/sidebar/__tests__/searchbar.test.tsx b/dashboards-observability/public/components/metrics/sidebar/__tests__/searchbar.test.tsx index de824be1a..cc84dc0eb 100644 --- a/dashboards-observability/public/components/metrics/sidebar/__tests__/searchbar.test.tsx +++ b/dashboards-observability/public/components/metrics/sidebar/__tests__/searchbar.test.tsx @@ -8,17 +8,22 @@ import Adapter from 'enzyme-adapter-react-16'; import React from 'react'; import { waitFor } from '@testing-library/react'; import { SearchBar } from '../search_bar'; -import { sampleAllAvailableMetrics } from '../../../../../test/metrics_contants'; +import { Provider } from 'react-redux'; +import { applyMiddleware, createStore } from 'redux'; +import thunk from 'redux-thunk'; +import rootReducer from '../../../../framework/redux/reducers'; describe('Search Bar Component', () => { configure({ adapter: new Adapter() }); + const store = createStore(rootReducer, applyMiddleware(thunk)); it('Search Side Bar Component with no available metrics', async () => { - const allAvailableMetrics: any = []; - const handleAddMetric = jest.fn(); + const setSearch = jest.fn(); const wrapper = mount( - + + + ); wrapper.update(); @@ -29,11 +34,12 @@ describe('Search Bar Component', () => { }); it('Search Side Bar Component with available metrics', async () => { - const allAvailableMetrics = sampleAllAvailableMetrics; - const handleAddMetric = jest.fn(); + const setSearch = jest.fn(); const wrapper = mount( - + + + ); wrapper.update(); diff --git a/dashboards-observability/public/components/metrics/sidebar/__tests__/sidebar.test.tsx b/dashboards-observability/public/components/metrics/sidebar/__tests__/sidebar.test.tsx index 1cf39ca1b..747201fa7 100644 --- a/dashboards-observability/public/components/metrics/sidebar/__tests__/sidebar.test.tsx +++ b/dashboards-observability/public/components/metrics/sidebar/__tests__/sidebar.test.tsx @@ -24,10 +24,11 @@ describe('Side Bar Component', () => { const http = httpClientMock; const pplService = new PPLService(httpClientMock); + const search = false; const wrapper = mount( - + ); diff --git a/dashboards-observability/public/components/metrics/top_menu/__tests__/__snapshots__/top_menu.test.tsx.snap b/dashboards-observability/public/components/metrics/top_menu/__tests__/__snapshots__/top_menu.test.tsx.snap index 274f4b2f0..edf4f4490 100644 --- a/dashboards-observability/public/components/metrics/top_menu/__tests__/__snapshots__/top_menu.test.tsx.snap +++ b/dashboards-observability/public/components/metrics/top_menu/__tests__/__snapshots__/top_menu.test.tsx.snap @@ -84,12 +84,15 @@ exports[`Metrics Top Menu Component renders Top Menu Component when disabled in
- +
@@ -109,24 +112,24 @@ exports[`Metrics Top Menu Component renders Top Menu Component when disabled in className="euiFlexItem euiSearchBar__searchHolder" > @@ -211,18 +214,6 @@ exports[`Metrics Top Menu Component renders Top Menu Component when disabled in
- -
-
@@ -1405,12 +1396,15 @@ exports[`Metrics Top Menu Component renders Top Menu Component when disabled wit
- +
@@ -1430,24 +1424,24 @@ exports[`Metrics Top Menu Component renders Top Menu Component when disabled wit className="euiFlexItem euiSearchBar__searchHolder" > @@ -1532,18 +1526,6 @@ exports[`Metrics Top Menu Component renders Top Menu Component when disabled wit
- -
-
@@ -2676,12 +2658,15 @@ exports[`Metrics Top Menu Component renders Top Menu Component when enabled 1`]
- +
@@ -2701,24 +2686,24 @@ exports[`Metrics Top Menu Component renders Top Menu Component when enabled 1`] className="euiFlexItem euiSearchBar__searchHolder" > @@ -2799,18 +2784,6 @@ exports[`Metrics Top Menu Component renders Top Menu Component when enabled 1`]
- -
-