From acb0d41937e30bd76c666a225407743243692d11 Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Mon, 3 Jun 2024 15:05:02 -0700 Subject: [PATCH] pick PR 6167 Signed-off-by: Joshua Li --- .../data_explorer/public/components/app.tsx | 24 +--- .../public/components/app_container.tsx | 114 +++++++++++------- .../view_components/utils/use_search.ts | 22 +++- 3 files changed, 92 insertions(+), 68 deletions(-) diff --git a/src/plugins/data_explorer/public/components/app.tsx b/src/plugins/data_explorer/public/components/app.tsx index ff6b5931a40..6b19413d17e 100644 --- a/src/plugins/data_explorer/public/components/app.tsx +++ b/src/plugins/data_explorer/public/components/app.tsx @@ -3,34 +3,12 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React, { useEffect } from 'react'; -import { useLocation } from 'react-router-dom'; +import React from 'react'; import { AppMountParameters } from '../../../../core/public'; import { useView } from '../utils/use'; import { AppContainer } from './app_container'; -import { useOpenSearchDashboards } from '../../../opensearch_dashboards_react/public'; -import { DataExplorerServices } from '../types'; -import { syncQueryStateWithUrl } from '../../../data/public'; export const DataExplorerApp = ({ params }: { params: AppMountParameters }) => { const { view } = useView(); - const { - services: { - data: { query }, - osdUrlStateStorage, - }, - } = useOpenSearchDashboards(); - const { pathname } = useLocation(); - - useEffect(() => { - // syncs `_g` portion of url with query services - const { stop } = syncQueryStateWithUrl(query, osdUrlStateStorage); - - return () => stop(); - - // this effect should re-run when pathname is changed to preserve querystring part, - // so the global state is always preserved - }, [query, osdUrlStateStorage, pathname]); - return ; }; diff --git a/src/plugins/data_explorer/public/components/app_container.tsx b/src/plugins/data_explorer/public/components/app_container.tsx index 52982914005..ef161d54e50 100644 --- a/src/plugins/data_explorer/public/components/app_container.tsx +++ b/src/plugins/data_explorer/public/components/app_container.tsx @@ -12,49 +12,75 @@ import { NoView } from './no_view'; import { View } from '../services/view_service/view'; import './app_container.scss'; -export const AppContainer = ({ view, params }: { view?: View; params: AppMountParameters }) => { - const isMobile = useIsWithinBreakpoints(['xs', 's', 'm']); - // TODO: Make this more robust. - if (!view) { - return ; +export const AppContainer = React.memo( + ({ view, params }: { view?: View; params: AppMountParameters }) => { + const isMobile = useIsWithinBreakpoints(['xs', 's', 'm']); + // TODO: Make this more robust. + if (!view) { + return ; + } + + const { Canvas, Panel, Context } = view; + + const MemoizedPanel = memo(Panel); + const MemoizedCanvas = memo(Canvas); + + // Render the application DOM. + return ( + + {/* TODO: improve fallback state */} + Loading...}> + + + {(EuiResizablePanel, EuiResizableButton) => ( + <> + + + + + + + + + + + + + + )} + + + + + ); + }, + (prevProps, nextProps) => { + return ( + prevProps.view === nextProps.view && + shallowEqual(prevProps.params, nextProps.params, ['history']) + ); + } +); + +// A simple shallow equal function that can ignore specified keys +function shallowEqual(object1: any, object2: any, ignoreKeys: any) { + const keys1 = Object.keys(object1).filter((key) => !ignoreKeys.includes(key)); + const keys2 = Object.keys(object2).filter((key) => !ignoreKeys.includes(key)); + + if (keys1.length !== keys2.length) { + return false; + } + + for (const key of keys1) { + if (object1[key] !== object2[key]) { + return false; + } } - const { Canvas, Panel, Context } = view; - - const MemoizedPanel = memo(Panel); - const MemoizedCanvas = memo(Canvas); - - // Render the application DOM. - return ( - - {/* TODO: improve fallback state */} - Loading...}> - - - {(EuiResizablePanel, EuiResizableButton) => ( - <> - - - - - - - - - - - - - - )} - - - - - ); -}; + return true; +} diff --git a/src/plugins/discover/public/application/view_components/utils/use_search.ts b/src/plugins/discover/public/application/view_components/utils/use_search.ts index 9da9704f32a..e3a84ae8463 100644 --- a/src/plugins/discover/public/application/view_components/utils/use_search.ts +++ b/src/plugins/discover/public/application/view_components/utils/use_search.ts @@ -9,6 +9,7 @@ import { debounceTime } from 'rxjs/operators'; import { i18n } from '@osd/i18n'; import { useEffect } from 'react'; import { cloneDeep } from 'lodash'; +import { useLocation } from 'react-router-dom'; import { RequestAdapter } from '../../../../../inspector/public'; import { DiscoverViewServices } from '../../../build_services'; import { search } from '../../../../../data/public'; @@ -31,6 +32,7 @@ import { getResponseInspectorStats, } from '../../../opensearch_dashboards_services'; import { SEARCH_ON_PAGE_LOAD_SETTING } from '../../../../common'; +import { syncQueryStateWithUrl } from '../../../../../data/public'; export enum ResultStatus { UNINITIALIZED = 'uninitialized', @@ -68,11 +70,19 @@ export type RefetchSubject = Subject; * }, [data$]); */ export const useSearch = (services: DiscoverViewServices) => { + const { pathname } = useLocation(); const initalSearchComplete = useRef(false); const [savedSearch, setSavedSearch] = useState(undefined); const { savedSearch: savedSearchId, sort, interval } = useSelector((state) => state.discover); - const { data, filterManager, getSavedSearchById, core, toastNotifications, chrome } = services; const indexPattern = useIndexPattern(services); + const { + data, + filterManager, + getSavedSearchById, + core, + toastNotifications, + osdUrlStateStorage, + } = services; const timefilter = data.query.timefilter.timefilter; const fetchStateRef = useRef<{ abortController: AbortController | undefined; @@ -309,6 +319,16 @@ export const useSearch = (services: DiscoverViewServices) => { // eslint-disable-next-line react-hooks/exhaustive-deps }, [getSavedSearchById, savedSearchId]); + useEffect(() => { + // syncs `_g` portion of url with query services + const { stop } = syncQueryStateWithUrl(data.query, osdUrlStateStorage); + + return () => stop(); + + // this effect should re-run when pathname is changed to preserve querystring part, + // so the global state is always preserved + }, [data.query, osdUrlStateStorage, pathname]); + return { data$, refetch$,