Skip to content

Commit 08bd272

Browse files
[Metrics UI] Fix saving/loading saved views from URL (#90216)
Co-authored-by: Kibana Machine <[email protected]>
1 parent 9d8296e commit 08bd272

File tree

4 files changed

+60
-22
lines changed

4 files changed

+60
-22
lines changed

x-pack/plugins/infra/public/components/saved_views/toolbar_control.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
*/
77

88
import { EuiFlexGroup } from '@elastic/eui';
9-
import React, { useCallback, useState, useEffect, useContext } from 'react';
9+
import React, { useCallback, useState, useEffect } from 'react';
1010
import { i18n } from '@kbn/i18n';
1111
import { FormattedMessage } from '@kbn/i18n/react';
1212
import {
@@ -21,7 +21,7 @@ import { SavedViewCreateModal } from './create_modal';
2121
import { SavedViewUpdateModal } from './update_modal';
2222
import { SavedViewManageViewsFlyout } from './manage_views_flyout';
2323
import { useKibana } from '../../../../../../src/plugins/kibana_react/public';
24-
import { SavedView } from '../../containers/saved_view/saved_view';
24+
import { useSavedViewContext } from '../../containers/saved_view/saved_view';
2525
import { SavedViewListModal } from './view_list_modal';
2626

2727
interface Props<ViewState> {
@@ -47,7 +47,7 @@ export function SavedViewsToolbarControls<ViewState>(props: Props<ViewState>) {
4747
updatedView,
4848
currentView,
4949
setCurrentView,
50-
} = useContext(SavedView.Context);
50+
} = useSavedViewContext();
5151
const [modalOpen, setModalOpen] = useState(false);
5252
const [viewListModalOpen, setViewListModalOpen] = useState(false);
5353
const [isInvalid, setIsInvalid] = useState(false);

x-pack/plugins/infra/public/containers/saved_view/saved_view.tsx

Lines changed: 51 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,14 @@
66
*/
77

88
import createContainer from 'constate';
9+
import * as rt from 'io-ts';
10+
import { pipe } from 'fp-ts/lib/pipeable';
11+
import { fold } from 'fp-ts/lib/Either';
12+
import { constant, identity } from 'fp-ts/lib/function';
913
import { useCallback, useMemo, useState, useEffect, useContext } from 'react';
1014
import { i18n } from '@kbn/i18n';
1115
import { SimpleSavedObject, SavedObjectAttributes } from 'kibana/public';
16+
import { useUrlState } from '../../utils/use_url_state';
1217
import { useFindSavedObject } from '../../hooks/use_find_saved_object';
1318
import { useCreateSavedObject } from '../../hooks/use_create_saved_object';
1419
import { useDeleteSavedObject } from '../../hooks/use_delete_saved_object';
@@ -39,6 +44,14 @@ interface Props {
3944
shouldLoadDefault: boolean;
4045
}
4146

47+
const savedViewUrlStateRT = rt.type({
48+
viewId: rt.string,
49+
});
50+
type SavedViewUrlState = rt.TypeOf<typeof savedViewUrlStateRT>;
51+
const DEFAULT_SAVED_VIEW_STATE: SavedViewUrlState = {
52+
viewId: '0',
53+
};
54+
4255
export const useSavedView = (props: Props) => {
4356
const {
4457
source,
@@ -52,6 +65,13 @@ export const useSavedView = (props: Props) => {
5265
const { data, loading, find, error: errorOnFind, hasView } = useFindSavedObject<
5366
SavedViewSavedObject<ViewState>
5467
>(viewType);
68+
const [urlState, setUrlState] = useUrlState<SavedViewUrlState>({
69+
defaultState: DEFAULT_SAVED_VIEW_STATE,
70+
decodeUrlState,
71+
encodeUrlState,
72+
urlStateKey: 'savedView',
73+
});
74+
5575
const [shouldLoadDefault] = useState(props.shouldLoadDefault);
5676
const [currentView, setCurrentView] = useState<SavedView<any> | null>(null);
5777
const [loadingDefaultView, setLoadingDefaultView] = useState<boolean | null>(null);
@@ -212,25 +232,35 @@ export const useSavedView = (props: Props) => {
212232
});
213233
}, [setCurrentView, defaultViewId, defaultViewState]);
214234

215-
useEffect(() => {
216-
if (loadingDefaultView || currentView || !shouldLoadDefault) {
217-
return;
218-
}
219-
235+
const loadDefaultViewIfSet = useCallback(() => {
220236
if (defaultViewId !== '0') {
221237
loadDefaultView();
222238
} else {
223239
setDefault();
224240
setLoadingDefaultView(false);
225241
}
226-
}, [
227-
loadDefaultView,
228-
shouldLoadDefault,
229-
setDefault,
230-
loadingDefaultView,
231-
currentView,
232-
defaultViewId,
233-
]);
242+
}, [defaultViewId, loadDefaultView, setDefault, setLoadingDefaultView]);
243+
244+
useEffect(() => {
245+
if (loadingDefaultView || currentView || !shouldLoadDefault) {
246+
return;
247+
}
248+
249+
loadDefaultViewIfSet();
250+
}, [loadDefaultViewIfSet, loadingDefaultView, currentView, shouldLoadDefault]);
251+
252+
useEffect(() => {
253+
if (currentView && urlState.viewId !== currentView.id && data)
254+
setUrlState({ viewId: currentView.id });
255+
}, [urlState, setUrlState, currentView, defaultViewId, data]);
256+
257+
useEffect(() => {
258+
if (!currentView && !loading && data) {
259+
const viewToSet = views.find((v) => v.id === urlState.viewId);
260+
if (viewToSet) setCurrentView(viewToSet);
261+
else loadDefaultViewIfSet();
262+
}
263+
}, [loading, currentView, data, views, setCurrentView, loadDefaultViewIfSet, urlState.viewId]);
234264

235265
return {
236266
views,
@@ -260,3 +290,11 @@ export const useSavedView = (props: Props) => {
260290

261291
export const SavedView = createContainer(useSavedView);
262292
export const [SavedViewProvider, useSavedViewContext] = SavedView;
293+
294+
const encodeUrlState = (state: SavedViewUrlState) => {
295+
return savedViewUrlStateRT.encode(state);
296+
};
297+
const decodeUrlState = (value: unknown) => {
298+
const state = pipe(savedViewUrlStateRT.decode(value), fold(constant(undefined), identity));
299+
return state;
300+
};

x-pack/plugins/infra/public/pages/metrics/index.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ import { WaffleTimeProvider } from './inventory_view/hooks/use_waffle_time';
3636
import { WaffleFiltersProvider } from './inventory_view/hooks/use_waffle_filters';
3737

3838
import { MetricsAlertDropdown } from '../../alerting/common/components/metrics_alert_dropdown';
39-
import { SavedView } from '../../containers/saved_view/saved_view';
39+
import { SavedViewProvider } from '../../containers/saved_view/saved_view';
4040
import { AlertPrefillProvider } from '../../alerting/use_alert_prefill';
4141
import { InfraMLCapabilitiesProvider } from '../../containers/ml/infra_ml_capabilities';
4242
import { AnomalyDetectionFlyout } from './inventory_view/components/ml/anomaly_detection/anomaly_detection_flyout';
@@ -195,7 +195,7 @@ const PageContent = (props: {
195195
const { options } = useContext(MetricsExplorerOptionsContainer.Context);
196196

197197
return (
198-
<SavedView.Provider
198+
<SavedViewProvider
199199
shouldLoadDefault={options.source === 'default'}
200200
viewType={'metrics-explorer-view'}
201201
defaultViewState={DEFAULT_METRICS_EXPLORER_VIEW_STATE}
@@ -205,6 +205,6 @@ const PageContent = (props: {
205205
source={configuration}
206206
{...props}
207207
/>
208-
</SavedView.Provider>
208+
</SavedViewProvider>
209209
);
210210
};

x-pack/plugins/infra/public/pages/metrics/inventory_view/index.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import { useTrackPageview } from '../../../../../observability/public';
2323
import { useKibana } from '../../../../../../../src/plugins/kibana_react/public';
2424
import { Layout } from './components/layout';
2525
import { useLinkProps } from '../../../hooks/use_link_props';
26-
import { SavedView } from '../../../containers/saved_view/saved_view';
26+
import { SavedViewProvider } from '../../../containers/saved_view/saved_view';
2727
import { DEFAULT_WAFFLE_VIEW_STATE } from './hooks/use_waffle_view_state';
2828
import { useWaffleOptionsContext } from './hooks/use_waffle_options';
2929

@@ -64,13 +64,13 @@ export const SnapshotPage = () => {
6464
) : metricIndicesExist ? (
6565
<>
6666
<FilterBar />
67-
<SavedView.Provider
67+
<SavedViewProvider
6868
shouldLoadDefault={optionsSource === 'default'}
6969
viewType={'inventory-view'}
7070
defaultViewState={DEFAULT_WAFFLE_VIEW_STATE}
7171
>
7272
<Layout />
73-
</SavedView.Provider>
73+
</SavedViewProvider>
7474
</>
7575
) : hasFailedLoadingSource ? (
7676
<SourceErrorPage errorMessage={loadSourceFailureMessage || ''} retry={loadSource} />

0 commit comments

Comments
 (0)