-
Notifications
You must be signed in to change notification settings - Fork 885
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Vis Builder] global data persistence for vis builder #2896
Changes from all commits
2116222
efb7f22
616c48e
a146674
e372335
2924e1e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,13 +4,17 @@ | |
*/ | ||
|
||
import { i18n } from '@osd/i18n'; | ||
import { BehaviorSubject } from 'rxjs'; | ||
import { filter, map } from 'rxjs/operators'; | ||
Comment on lines
+7
to
+8
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit - just import operators, and then destruct later? |
||
import { | ||
AppMountParameters, | ||
AppNavLinkStatus, | ||
AppUpdater, | ||
CoreSetup, | ||
CoreStart, | ||
Plugin, | ||
PluginInitializerContext, | ||
ScopedHistory, | ||
} from '../../../core/public'; | ||
import { | ||
VisBuilderPluginSetupDependencies, | ||
|
@@ -41,10 +45,17 @@ import { | |
setUISettings, | ||
setTypeService, | ||
setReactExpressionRenderer, | ||
setQueryService, | ||
} from './plugin_services'; | ||
import { createSavedVisBuilderLoader } from './saved_visualizations'; | ||
import { registerDefaultTypes } from './visualizations'; | ||
import { ConfigSchema } from '../config'; | ||
import { | ||
createOsdUrlStateStorage, | ||
createOsdUrlTracker, | ||
withNotifyOnErrors, | ||
} from '../../opensearch_dashboards_utils/public'; | ||
import { opensearchFilters } from '../../data/public'; | ||
|
||
export class VisBuilderPlugin | ||
implements | ||
|
@@ -55,13 +66,45 @@ export class VisBuilderPlugin | |
VisBuilderPluginStartDependencies | ||
> { | ||
private typeService = new TypeService(); | ||
private appStateUpdater = new BehaviorSubject<AppUpdater>(() => ({})); | ||
private stopUrlTracking?: () => void; | ||
private currentHistory?: ScopedHistory; | ||
|
||
constructor(public initializerContext: PluginInitializerContext<ConfigSchema>) {} | ||
|
||
public setup( | ||
core: CoreSetup<VisBuilderPluginStartDependencies, VisBuilderStart>, | ||
{ embeddable, visualizations }: VisBuilderPluginSetupDependencies | ||
{ embeddable, visualizations, data }: VisBuilderPluginSetupDependencies | ||
) { | ||
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), | ||
Comment on lines
+90
to
+94
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is the purpose of this pipe? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is for the pinned filter. If the filter is pinned, then the filter will persist across the entire dashboards, and it will be stored in a global state('_g' part of the URL); if the filter is unpinned, then the filter will only persist on that specific app, but not across the entire dashboards, and the it will only be saved in '_a', not '_g'. Added a video in description to better demonstrate. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for the context :) |
||
})) | ||
), | ||
}, | ||
], | ||
getHistory: () => { | ||
return this.currentHistory!; | ||
}, | ||
}); | ||
this.stopUrlTracking = () => { | ||
stopUrlTracker(); | ||
}; | ||
|
||
// Register Default Visualizations | ||
const typeService = this.typeService; | ||
registerDefaultTypes(typeService.setup()); | ||
|
||
|
@@ -70,43 +113,62 @@ export class VisBuilderPlugin | |
id: PLUGIN_ID, | ||
title: PLUGIN_NAME, | ||
navLinkStatus: AppNavLinkStatus.hidden, | ||
async mount(params: AppMountParameters) { | ||
defaultPath: '#/', | ||
mount: async (params: AppMountParameters) => { | ||
// Load application bundle | ||
const { renderApp } = await import('./application'); | ||
|
||
// Get start services as specified in opensearch_dashboards.json | ||
const [coreStart, pluginsStart, selfStart] = await core.getStartServices(); | ||
const { data, savedObjects, navigation, expressions } = pluginsStart; | ||
const { savedObjects, navigation, expressions } = pluginsStart; | ||
this.currentHistory = params.history; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Whats the difference between scoped and current history? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. They are the same thing. Setting the currentHistory to be params.history here since currentHistory is being used in
we set scopedHistory to be currentHistory too when we set up the services:
|
||
|
||
// make sure the index pattern list is up to date | ||
data.indexPatterns.clearCache(); | ||
pluginsStart.data.indexPatterns.clearCache(); | ||
// make sure a default index pattern exists | ||
// if not, the page will be redirected to management and visualize won't be rendered | ||
// TODO: Add the redirect | ||
await pluginsStart.data.indexPatterns.ensureDefaultIndexPattern(); | ||
|
||
// Register Default Visualizations | ||
appMounted(); | ||
|
||
// dispatch synthetic hash change event to update hash history objects | ||
// this is necessary because hash updates triggered by using popState won't trigger this event naturally. | ||
const unlistenParentHistory = this.currentHistory.listen(() => { | ||
window.dispatchEvent(new HashChangeEvent('hashchange')); | ||
}); | ||
|
||
const services: VisBuilderServices = { | ||
...coreStart, | ||
scopedHistory: this.currentHistory, | ||
history: this.currentHistory, | ||
osdUrlStateStorage: createOsdUrlStateStorage({ | ||
history: this.currentHistory, | ||
useHash: coreStart.uiSettings.get('state:storeInSessionStorage'), | ||
...withNotifyOnErrors(coreStart.notifications.toasts), | ||
}), | ||
toastNotifications: coreStart.notifications.toasts, | ||
data, | ||
data: pluginsStart.data, | ||
savedObjectsPublic: savedObjects, | ||
navigation, | ||
expressions, | ||
history: params.history, | ||
setHeaderActionMenu: params.setHeaderActionMenu, | ||
types: typeService.start(), | ||
savedVisBuilderLoader: selfStart.savedVisBuilderLoader, | ||
embeddable: pluginsStart.embeddable, | ||
scopedHistory: params.history, | ||
dashboard: pluginsStart.dashboard, | ||
}; | ||
|
||
// Instantiate the store | ||
const store = await getPreloadedStore(services); | ||
const unmount = renderApp(params, services, store); | ||
|
||
// Render the application | ||
abbyhu2000 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return renderApp(params, services, store); | ||
return () => { | ||
unlistenParentHistory(); | ||
unmount(); | ||
appUnMounted(); | ||
}; | ||
}, | ||
}); | ||
|
||
|
@@ -154,7 +216,7 @@ export class VisBuilderPlugin | |
|
||
public start( | ||
core: CoreStart, | ||
{ data, expressions }: VisBuilderPluginStartDependencies | ||
{ expressions, data }: VisBuilderPluginStartDependencies | ||
abbyhu2000 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
): VisBuilderStart { | ||
const typeService = this.typeService.start(); | ||
|
||
|
@@ -176,12 +238,17 @@ export class VisBuilderPlugin | |
setTimeFilter(data.query.timefilter.timefilter); | ||
setTypeService(typeService); | ||
setUISettings(core.uiSettings); | ||
setQueryService(data.query); | ||
|
||
return { | ||
...typeService, | ||
savedVisBuilderLoader, | ||
}; | ||
} | ||
|
||
public stop() {} | ||
public stop() { | ||
if (this.stopUrlTracking) { | ||
this.stopUrlTracking(); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how come this file has the old license? i believe this is a new plugin right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think it's because this file is very similar to the get_top_nav_config.tsx in visualize plugin?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep - mostly copied.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
probably we should update it