Skip to content

Commit

Permalink
Adds global state persistence to data explorer
Browse files Browse the repository at this point in the history
Signed-off-by: Ashwin P Chandran <ashwinpc@amazon.com>
  • Loading branch information
ashwin-pc committed Jul 17, 2023
1 parent 5981002 commit 031fc07
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 31 deletions.
25 changes: 11 additions & 14 deletions src/plugins/data_explorer/public/components/sidebar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,12 @@

import React, { useMemo, FC, useEffect, useState } from 'react';
import { i18n } from '@osd/i18n';
import {
EuiPanel,
EuiComboBox,
EuiSelect,
EuiSelectOption,
EuiComboBoxOptionOption,
} from '@elastic/eui';
import { EuiPanel, EuiComboBox, EuiSelect, EuiComboBoxOptionOption } from '@elastic/eui';
import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public';
import { useView } from '../../utils/use';
import { DataExplorerServices } from '../../types';
import { useTypedDispatch, useTypedSelector, setIndexPattern } from '../../utils/state_management';
import { setView } from '../../utils/state_management/metadata_slice';

export const Sidebar: FC = ({ children }) => {
const { indexPattern: indexPatternId } = useTypedSelector((state) => state.metadata);
Expand All @@ -24,7 +19,7 @@ export const Sidebar: FC = ({ children }) => {
const [selectedOption, setSelectedOption] = useState<EuiComboBoxOptionOption<string>>();
const { view, viewRegistry } = useView();
const views = viewRegistry.all();
const viewOptions: EuiSelectOption[] = useMemo(
const viewOptions = useMemo(
() =>
views.map(({ id, title }) => ({
value: id,
Expand Down Expand Up @@ -87,14 +82,16 @@ export const Sidebar: FC = ({ children }) => {
return;
}

dispatch(
setIndexPattern({
state: value,
})
);
dispatch(setIndexPattern(value));
}}
/>
<EuiSelect
options={viewOptions}
value={view?.id}
onChange={(e) => {
dispatch(setView(e.target.value));
}}
/>
<EuiSelect options={viewOptions} value={view?.id} />
</EuiPanel>
{children}
</>
Expand Down
46 changes: 44 additions & 2 deletions src/plugins/data_explorer/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@
* SPDX-License-Identifier: Apache-2.0
*/

import { BehaviorSubject } from 'rxjs';
import { filter, map } from 'rxjs/operators';
import {
AppMountParameters,
CoreSetup,
CoreStart,
Plugin,
AppNavLinkStatus,
ScopedHistory,
AppUpdater,
} from '../../../core/public';
import {
DataExplorerPluginSetup,
Expand All @@ -22,9 +25,11 @@ import { PLUGIN_ID, PLUGIN_NAME } from '../common';
import { ViewService } from './services/view_service';
import {
createOsdUrlStateStorage,
createOsdUrlTracker,
withNotifyOnErrors,
} from '../../opensearch_dashboards_utils/public';
import { getPreloadedStore } from './utils/state_management';
import { opensearchFilters } from '../../data/public';

export class DataExplorerPlugin
implements
Expand All @@ -35,16 +40,47 @@ export class DataExplorerPlugin
DataExplorerPluginStartDependencies
> {
private viewService = new ViewService();
private appStateUpdater = new BehaviorSubject<AppUpdater>(() => ({}));
private stopUrlTracking?: () => void;
private currentHistory?: ScopedHistory;

public setup(
core: CoreSetup<DataExplorerPluginStartDependencies, DataExplorerPluginStart>
core: CoreSetup<DataExplorerPluginStartDependencies, DataExplorerPluginStart>,
{ data }: DataExplorerPluginSetupDependencies
): DataExplorerPluginSetup {
const viewService = this.viewService;
// TODO: Remove this before merge to main
// eslint-disable-next-line no-console
console.log('data_explorer: Setup');

const { appMounted, appUnMounted, stop: stopUrlTracker } = createOsdUrlTracker({
baseUrl: core.http.basePath.prepend(`/app/${PLUGIN_ID}`),
defaultSubUrl: '#/',
storageKey: `lastUrl:${core.http.basePath.get()}:${PLUGIN_ID}`,
navLinkUpdater$: this.appStateUpdater,
toastNotifications: core.notifications.toasts,
stateParams: [
{
osdUrlKey: '_g',
stateUpdate$: data.query.state$.pipe(
filter(
({ changes }) => !!(changes.globalFilters || changes.time || changes.refreshInterval)
),
map(({ state }) => ({
...state,
filters: state.filters?.filter(opensearchFilters.isFilterPinned),
}))
),
},
],
getHistory: () => {
return this.currentHistory!;
},
});
this.stopUrlTracking = () => {
stopUrlTracker();
};

// Register an application into the side navigation menu
core.application.register({
id: PLUGIN_ID,
Expand Down Expand Up @@ -83,9 +119,11 @@ export class DataExplorerPlugin
services.store = store;

const unmount = renderApp(coreStart, services, params, store);
appMounted();

return () => {
unsubscribeStore();
appUnMounted();
unmount();
};
},
Expand All @@ -103,5 +141,9 @@ export class DataExplorerPlugin
return {};
}

public stop() {}
public stop() {
if (this.stopUrlTracking) {
this.stopUrlTracking();
}
}
}
8 changes: 5 additions & 3 deletions src/plugins/data_explorer/public/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,18 @@ import { EmbeddableStart } from '../../embeddable/public';
import { ExpressionsStart } from '../../expressions/public';
import { ViewServiceStart, ViewServiceSetup } from './services/view_service';
import { IOsdUrlStateStorage } from '../../opensearch_dashboards_utils/public';
import { DataPublicPluginStart } from '../../data/public';
import { DataPublicPluginSetup, DataPublicPluginStart } from '../../data/public';
import { Store } from './utils/state_management';

export type DataExplorerPluginSetup = ViewServiceSetup;

// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface DataExplorerPluginStart {}

// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface DataExplorerPluginSetupDependencies {}
export interface DataExplorerPluginSetupDependencies {
data: DataPublicPluginSetup;
}

export interface DataExplorerPluginStartDependencies {
expressions: ExpressionsStart;
embeddable: EmbeddableStart;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { DataExplorerServices } from '../../types';
export interface MetadataState {
indexPattern?: string;
originatingApp?: string;
view?: string;
}

const initialState: MetadataState = {};
Expand Down Expand Up @@ -36,11 +37,14 @@ export const slice = createSlice({
name: 'metadata',
initialState,
reducers: {
setIndexPattern: (state, action: PayloadAction<{ state?: string }>) => {
state.indexPattern = action.payload.state;
setIndexPattern: (state, action: PayloadAction<string>) => {
state.indexPattern = action.payload;
},
setOriginatingApp: (state, action: PayloadAction<{ state?: string }>) => {
state.originatingApp = action.payload.state;
setOriginatingApp: (state, action: PayloadAction<string | undefined>) => {
state.originatingApp = action.payload;
},
setView: (state, action: PayloadAction<string>) => {
state.view = action.payload;
},
setState: (_state, action: PayloadAction<MetadataState>) => {
return action.payload;
Expand All @@ -49,4 +53,4 @@ export const slice = createSlice({
});

export const { reducer } = slice;
export const { setIndexPattern, setOriginatingApp, setState } = slice.actions;
export const { setIndexPattern, setOriginatingApp, setView, setState } = slice.actions;
23 changes: 16 additions & 7 deletions src/plugins/data_explorer/public/utils/use/use_view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,33 @@
* SPDX-License-Identifier: Apache-2.0
*/

import { useEffect, useState } from 'react';
import { useEffect, useMemo } from 'react';
import { useParams } from 'react-router-dom';
import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public';
import { View } from '../../services/view_service/view';
import { DataExplorerServices } from '../../types';
import { useTypedDispatch, useTypedSelector } from '../state_management';
import { setView } from '../state_management/metadata_slice';

export const useView = () => {
// TODO: Move the view to the redux store once the store is ready
const [view, setView] = useState<View | undefined>();
const { appId } = useParams<{ appId: string }>();
const viewId = useTypedSelector((state) => state.metadata.view);
const {
services: { viewRegistry },
} = useOpenSearchDashboards<DataExplorerServices>();
const dispatch = useTypedDispatch();
const { appId } = useParams<{ appId: string }>();

const view = useMemo(() => {
if (!viewId) return undefined;
return viewRegistry.get(viewId);
}, [viewId, viewRegistry]);

useEffect(() => {
const currentView = viewRegistry.get(appId);
setView(currentView);
}, [appId, viewRegistry]);

if (!currentView) return;

dispatch(setView(currentView?.id));
}, [appId, dispatch, viewRegistry]);

return { view, viewRegistry };
};

0 comments on commit 031fc07

Please sign in to comment.