Skip to content

Commit acb0d41

Browse files
committed
pick PR 6167
Signed-off-by: Joshua Li <joshuali925@gmail.com>
1 parent 0771a0d commit acb0d41

File tree

3 files changed

+92
-68
lines changed

3 files changed

+92
-68
lines changed

src/plugins/data_explorer/public/components/app.tsx

+1-23
Original file line numberDiff line numberDiff line change
@@ -3,34 +3,12 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
import React, { useEffect } from 'react';
7-
import { useLocation } from 'react-router-dom';
6+
import React from 'react';
87
import { AppMountParameters } from '../../../../core/public';
98
import { useView } from '../utils/use';
109
import { AppContainer } from './app_container';
11-
import { useOpenSearchDashboards } from '../../../opensearch_dashboards_react/public';
12-
import { DataExplorerServices } from '../types';
13-
import { syncQueryStateWithUrl } from '../../../data/public';
1410

1511
export const DataExplorerApp = ({ params }: { params: AppMountParameters }) => {
1612
const { view } = useView();
17-
const {
18-
services: {
19-
data: { query },
20-
osdUrlStateStorage,
21-
},
22-
} = useOpenSearchDashboards<DataExplorerServices>();
23-
const { pathname } = useLocation();
24-
25-
useEffect(() => {
26-
// syncs `_g` portion of url with query services
27-
const { stop } = syncQueryStateWithUrl(query, osdUrlStateStorage);
28-
29-
return () => stop();
30-
31-
// this effect should re-run when pathname is changed to preserve querystring part,
32-
// so the global state is always preserved
33-
}, [query, osdUrlStateStorage, pathname]);
34-
3513
return <AppContainer view={view} params={params} />;
3614
};

src/plugins/data_explorer/public/components/app_container.tsx

+70-44
Original file line numberDiff line numberDiff line change
@@ -12,49 +12,75 @@ import { NoView } from './no_view';
1212
import { View } from '../services/view_service/view';
1313
import './app_container.scss';
1414

15-
export const AppContainer = ({ view, params }: { view?: View; params: AppMountParameters }) => {
16-
const isMobile = useIsWithinBreakpoints(['xs', 's', 'm']);
17-
// TODO: Make this more robust.
18-
if (!view) {
19-
return <NoView />;
15+
export const AppContainer = React.memo(
16+
({ view, params }: { view?: View; params: AppMountParameters }) => {
17+
const isMobile = useIsWithinBreakpoints(['xs', 's', 'm']);
18+
// TODO: Make this more robust.
19+
if (!view) {
20+
return <NoView />;
21+
}
22+
23+
const { Canvas, Panel, Context } = view;
24+
25+
const MemoizedPanel = memo(Panel);
26+
const MemoizedCanvas = memo(Canvas);
27+
28+
// Render the application DOM.
29+
return (
30+
<EuiPage className="deLayout" paddingSize="none">
31+
{/* TODO: improve fallback state */}
32+
<Suspense fallback={<div>Loading...</div>}>
33+
<Context {...params}>
34+
<EuiResizableContainer direction={isMobile ? 'vertical' : 'horizontal'}>
35+
{(EuiResizablePanel, EuiResizableButton) => (
36+
<>
37+
<EuiResizablePanel
38+
initialSize={20}
39+
minSize="260px"
40+
mode={['collapsible', { position: 'top' }]}
41+
paddingSize="none"
42+
>
43+
<Sidebar>
44+
<MemoizedPanel {...params} />
45+
</Sidebar>
46+
</EuiResizablePanel>
47+
<EuiResizableButton />
48+
49+
<EuiResizablePanel initialSize={80} minSize="65%" mode="main" paddingSize="none">
50+
<EuiPageBody className="deLayout__canvas">
51+
<MemoizedCanvas {...params} />
52+
</EuiPageBody>
53+
</EuiResizablePanel>
54+
</>
55+
)}
56+
</EuiResizableContainer>
57+
</Context>
58+
</Suspense>
59+
</EuiPage>
60+
);
61+
},
62+
(prevProps, nextProps) => {
63+
return (
64+
prevProps.view === nextProps.view &&
65+
shallowEqual(prevProps.params, nextProps.params, ['history'])
66+
);
67+
}
68+
);
69+
70+
// A simple shallow equal function that can ignore specified keys
71+
function shallowEqual(object1: any, object2: any, ignoreKeys: any) {
72+
const keys1 = Object.keys(object1).filter((key) => !ignoreKeys.includes(key));
73+
const keys2 = Object.keys(object2).filter((key) => !ignoreKeys.includes(key));
74+
75+
if (keys1.length !== keys2.length) {
76+
return false;
77+
}
78+
79+
for (const key of keys1) {
80+
if (object1[key] !== object2[key]) {
81+
return false;
82+
}
2083
}
2184

22-
const { Canvas, Panel, Context } = view;
23-
24-
const MemoizedPanel = memo(Panel);
25-
const MemoizedCanvas = memo(Canvas);
26-
27-
// Render the application DOM.
28-
return (
29-
<EuiPage className="deLayout" paddingSize="none">
30-
{/* TODO: improve fallback state */}
31-
<Suspense fallback={<div>Loading...</div>}>
32-
<Context {...params}>
33-
<EuiResizableContainer direction={isMobile ? 'vertical' : 'horizontal'}>
34-
{(EuiResizablePanel, EuiResizableButton) => (
35-
<>
36-
<EuiResizablePanel
37-
initialSize={20}
38-
minSize="260px"
39-
mode={['collapsible', { position: 'top' }]}
40-
paddingSize="none"
41-
>
42-
<Sidebar>
43-
<MemoizedPanel {...params} />
44-
</Sidebar>
45-
</EuiResizablePanel>
46-
<EuiResizableButton />
47-
48-
<EuiResizablePanel initialSize={80} minSize="65%" mode="main" paddingSize="none">
49-
<EuiPageBody className="deLayout__canvas">
50-
<MemoizedCanvas {...params} />
51-
</EuiPageBody>
52-
</EuiResizablePanel>
53-
</>
54-
)}
55-
</EuiResizableContainer>
56-
</Context>
57-
</Suspense>
58-
</EuiPage>
59-
);
60-
};
85+
return true;
86+
}

src/plugins/discover/public/application/view_components/utils/use_search.ts

+21-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { debounceTime } from 'rxjs/operators';
99
import { i18n } from '@osd/i18n';
1010
import { useEffect } from 'react';
1111
import { cloneDeep } from 'lodash';
12+
import { useLocation } from 'react-router-dom';
1213
import { RequestAdapter } from '../../../../../inspector/public';
1314
import { DiscoverViewServices } from '../../../build_services';
1415
import { search } from '../../../../../data/public';
@@ -31,6 +32,7 @@ import {
3132
getResponseInspectorStats,
3233
} from '../../../opensearch_dashboards_services';
3334
import { SEARCH_ON_PAGE_LOAD_SETTING } from '../../../../common';
35+
import { syncQueryStateWithUrl } from '../../../../../data/public';
3436

3537
export enum ResultStatus {
3638
UNINITIALIZED = 'uninitialized',
@@ -68,11 +70,19 @@ export type RefetchSubject = Subject<SearchRefetch>;
6870
* }, [data$]);
6971
*/
7072
export const useSearch = (services: DiscoverViewServices) => {
73+
const { pathname } = useLocation();
7174
const initalSearchComplete = useRef(false);
7275
const [savedSearch, setSavedSearch] = useState<SavedSearch | undefined>(undefined);
7376
const { savedSearch: savedSearchId, sort, interval } = useSelector((state) => state.discover);
74-
const { data, filterManager, getSavedSearchById, core, toastNotifications, chrome } = services;
7577
const indexPattern = useIndexPattern(services);
78+
const {
79+
data,
80+
filterManager,
81+
getSavedSearchById,
82+
core,
83+
toastNotifications,
84+
osdUrlStateStorage,
85+
} = services;
7686
const timefilter = data.query.timefilter.timefilter;
7787
const fetchStateRef = useRef<{
7888
abortController: AbortController | undefined;
@@ -309,6 +319,16 @@ export const useSearch = (services: DiscoverViewServices) => {
309319
// eslint-disable-next-line react-hooks/exhaustive-deps
310320
}, [getSavedSearchById, savedSearchId]);
311321

322+
useEffect(() => {
323+
// syncs `_g` portion of url with query services
324+
const { stop } = syncQueryStateWithUrl(data.query, osdUrlStateStorage);
325+
326+
return () => stop();
327+
328+
// this effect should re-run when pathname is changed to preserve querystring part,
329+
// so the global state is always preserved
330+
}, [data.query, osdUrlStateStorage, pathname]);
331+
312332
return {
313333
data$,
314334
refetch$,

0 commit comments

Comments
 (0)