Skip to content

Commit

Permalink
[Visualize] Remove global state in visualize (#58352) (#59636)
Browse files Browse the repository at this point in the history
* Remove global state in visualize

* Fix saved query

* Update saved query handling

* Resolve merge conflicts

* Use new state syncing helpers

* Fix state behavior

* Prevent loosing the global state

* Update state syncing with url

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
  • Loading branch information
sulemanof and elasticmachine authored Mar 9, 2020
1 parent 5f06b79 commit adb65a7
Show file tree
Hide file tree
Showing 10 changed files with 118 additions and 201 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,8 @@
* directly where they are needed.
*/

export { State } from 'ui/state_management/state';
// @ts-ignore
export { GlobalStateProvider } from 'ui/state_management/global_state';
// @ts-ignore
export { StateManagementConfigProvider } from 'ui/state_management/config_provider';

export { subscribeWithScope } from 'ui/utils/subscribe_with_scope';
// @ts-ignore
export { EventsProvider } from 'ui/events';
export { registerTimefilterWithGlobalStateFactory } from 'ui/timefilter/setup_router';
// @ts-ignore
export { KbnUrlProvider, RedirectWhenMissingProvider } from 'ui/url';
export { absoluteToParsedUrl } from 'ui/url/absolute_to_parsed_url';
export { KibanaParsedUrl } from 'ui/url/kibana_parsed_url';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,11 @@ import { i18nDirective, i18nFilter, I18nProvider } from '@kbn/i18n/angular';
import { AppMountContext } from 'kibana/public';
import {
configureAppAngularModule,
GlobalStateProvider,
KbnUrlProvider,
RedirectWhenMissingProvider,
IPrivate,
PrivateProvider,
PromiseServiceCreator,
StateManagementConfigProvider,
} from '../legacy_imports';
import { NavigationPublicPluginStart as NavigationStart } from '../../../../../../plugins/navigation/public';
import {
Expand Down Expand Up @@ -87,55 +85,27 @@ function createLocalAngularModule(core: AppMountContext['core'], navigation: Nav
createLocalI18nModule();
createLocalPrivateModule();
createLocalPromiseModule();
createLocalConfigModule(core);
createLocalKbnUrlModule();
createLocalStateModule();
createLocalTopNavModule(navigation);

const visualizeAngularModule: IModule = angular.module(moduleName, [
...thirdPartyAngularDependencies,
'app/visualize/Config',
'app/visualize/I18n',
'app/visualize/Private',
'app/visualize/TopNav',
'app/visualize/State',
'app/visualize/KbnUrl',
'app/visualize/Promise',
]);
return visualizeAngularModule;
}

function createLocalStateModule() {
angular
.module('app/visualize/State', [
'app/visualize/Private',
'app/visualize/Config',
'app/visualize/KbnUrl',
'app/visualize/Promise',
])
.service('globalState', function(Private: IPrivate) {
return Private(GlobalStateProvider);
});
}

function createLocalKbnUrlModule() {
angular
.module('app/visualize/KbnUrl', ['app/visualize/Private', 'ngRoute'])
.service('kbnUrl', (Private: IPrivate) => Private(KbnUrlProvider))
.service('redirectWhenMissing', (Private: IPrivate) => Private(RedirectWhenMissingProvider));
}

function createLocalConfigModule(core: AppMountContext['core']) {
angular
.module('app/visualize/Config', ['app/visualize/Private'])
.provider('stateManagementConfig', StateManagementConfigProvider)
.provider('config', () => {
return {
$get: () => ({
get: core.uiSettings.get.bind(core.uiSettings),
}),
};
});
}

function createLocalPromiseModule() {
angular.module('app/visualize/Promise', []).service('Promise', PromiseServiceCreator);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@
refresh-interval="refreshInterval.value"
on-refresh-change="onRefreshChange"
show-save-query="showSaveQuery"
on-saved="onQuerySaved"
on-saved-query-updated="onSavedQueryUpdated"
on-saved="updateSavedQuery"
on-saved-query-updated="updateSavedQuery"
on-clear-saved-query="onClearSavedQuery"
>
</kbn-top-nav>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import angular from 'angular';
import _ from 'lodash';
import { Subscription } from 'rxjs';
import { map } from 'rxjs/operators';
import { i18n } from '@kbn/i18n';

import React from 'react';
Expand All @@ -29,13 +30,17 @@ import { VisualizeConstants } from '../visualize_constants';
import { getEditBreadcrumbs } from '../breadcrumbs';

import { addHelpMenuToAppChrome } from '../help_menu/help_menu_util';
import { FilterStateManager } from '../../../../../data/public';
import { unhashUrl } from '../../../../../../../plugins/kibana_utils/public';
import { kbnBaseUrl } from '../../../../../../../plugins/kibana_legacy/public';
import {
SavedObjectSaveModal,
showSaveModal,
} from '../../../../../../../plugins/saved_objects/public';
import {
esFilters,
connectToQueryState,
syncQueryStateWithUrl,
} from '../../../../../../../plugins/data/public';

import { initVisEditorDirective } from './visualization_editor';
import { initVisualizationDirective } from './visualization';
Expand Down Expand Up @@ -65,28 +70,21 @@ export function initEditorDirective(app, deps) {

function VisualizeAppController(
$scope,
$element,
$route,
$window,
$injector,
$timeout,
kbnUrl,
redirectWhenMissing,
Promise,
globalState,
config
kbnUrlStateStorage,
history
) {
const {
indexPatterns,
localStorage,
visualizeCapabilities,
share,
data: {
query: {
filterManager,
timefilter: { timefilter },
},
},
data: { query: queryService },
toastNotifications,
chrome,
getBasePath,
Expand All @@ -97,6 +95,17 @@ function VisualizeAppController(
setActiveUrl,
} = getServices();

const {
filterManager,
timefilter: { timefilter },
} = queryService;

// starts syncing `_g` portion of url with query services
const { stop: stopSyncingQueryServiceStateWithUrl } = syncQueryStateWithUrl(
queryService,
kbnUrlStateStorage
);

// Retrieve the resolved SavedVis instance.
const savedVis = $route.current.locals.savedVis;
const _applyVis = () => {
Expand Down Expand Up @@ -284,26 +293,24 @@ function VisualizeAppController(
linked: !!savedVis.savedSearchId,
};

const useHash = config.get('state:storeInSessionStorage');
const { stateContainer, stopStateSync } = useVisualizeAppState({
useHash,
stateDefaults,
kbnUrlStateStorage,
});

const filterStateManager = new FilterStateManager(
globalState,
() => {
// Temporary AppState replacement
return {
set filters(_filters) {
stateContainer.transitions.set('filters', _filters);
},
get filters() {
return stateContainer.getState().filters;
},
};
// sync initial app filters from state to filterManager
filterManager.setAppFilters(_.cloneDeep(stateContainer.getState().filters));
// setup syncing of app filters between appState and filterManager
const stopSyncingAppFilters = connectToQueryState(
queryService,
{
set: ({ filters }) => stateContainer.transitions.set('filters', filters),
get: () => ({ filters: stateContainer.getState().filters }),
state$: stateContainer.state$.pipe(map(state => ({ filters: state.filters }))),
},
filterManager
{
filters: esFilters.FilterStateStore.APP_STATE,
}
);

// The savedVis is pulled from elasticsearch, but the appState is pulled from the url, with the
Expand Down Expand Up @@ -335,6 +342,24 @@ function VisualizeAppController(
}
);

const updateSavedQueryFromUrl = savedQueryId => {
if (!savedQueryId) {
delete $scope.savedQuery;

return;
}

if ($scope.savedQuery && $scope.savedQuery.id === savedQueryId) {
return;
}

savedQueryService.getSavedQuery(savedQueryId).then(savedQuery => {
$scope.$evalAsync(() => {
$scope.updateSavedQuery(savedQuery);
});
});
};

function init() {
if (vis.indexPattern) {
$scope.indexPattern = vis.indexPattern;
Expand Down Expand Up @@ -388,14 +413,14 @@ function VisualizeAppController(
};

$scope.timeRange = timefilter.getTime();
$scope.opts = _.pick($scope, 'savedVis', 'isAddToDashMode');

const unsubscribeStateUpdates = stateContainer.subscribe(state => {
const newQuery = migrateLegacyQuery(state.query);
if (!_.isEqual(state.query, newQuery)) {
stateContainer.transitions.set('query', newQuery);
}
persistOnChange(state);
updateSavedQueryFromUrl(state.savedQuery);

// if the browser history was changed manually we need to reflect changes in the editor
if (!_.isEqual(vis.getState(), state.vis)) {
Expand All @@ -413,6 +438,9 @@ function VisualizeAppController(
$scope.$broadcast('render');
};

// update the query if savedQuery is stored
updateSavedQueryFromUrl(initialState.savedQuery);

const subscriptions = new Subscription();

subscriptions.add(
Expand All @@ -438,7 +466,7 @@ function VisualizeAppController(

// update the searchSource when query updates
$scope.fetch = function() {
const { query, filters, linked } = stateContainer.getState();
const { query, linked, filters } = stateContainer.getState();
$scope.query = query;
$scope.linked = linked;
savedVis.searchSource.setField('query', query);
Expand All @@ -451,7 +479,6 @@ function VisualizeAppController(
subscribeWithScope($scope, filterManager.getUpdates$(), {
next: () => {
$scope.filters = filterManager.getFilters();
$scope.globalFilters = filterManager.getGlobalFilters();
},
})
);
Expand All @@ -466,13 +493,14 @@ function VisualizeAppController(
$scope._handler.destroy();
}
savedVis.destroy();
filterStateManager.destroy();
subscriptions.unsubscribe();
$scope.vis.off('apply', _applyVis);

unsubscribePersisted();
unsubscribeStateUpdates();
stopStateSync();
stopSyncingQueryServiceStateWithUrl();
stopSyncingAppFilters();
});

$timeout(() => {
Expand Down Expand Up @@ -501,23 +529,14 @@ function VisualizeAppController(
});
};

$scope.onQuerySaved = savedQuery => {
$scope.savedQuery = savedQuery;
};

$scope.onSavedQueryUpdated = savedQuery => {
$scope.savedQuery = { ...savedQuery };
};

$scope.onClearSavedQuery = () => {
delete $scope.savedQuery;
stateContainer.transitions.removeSavedQuery(defaultQuery);
filterManager.setFilters(filterManager.getGlobalFilters());
$scope.fetch();
};

const updateStateFromSavedQuery = savedQuery => {
stateContainer.transitions.set('query', savedQuery.attributes.query);
stateContainer.transitions.updateFromSavedQuery(savedQuery);

const savedQueryFilters = savedQuery.attributes.filters || [];
const globalFilters = filterManager.getGlobalFilters();
Expand All @@ -532,25 +551,12 @@ function VisualizeAppController(
timefilter.setRefreshInterval(savedQuery.attributes.timefilter.refreshInterval);
}
}

$scope.fetch();
};

// update the query if savedQuery is stored
if (stateContainer.getState().savedQuery) {
savedQueryService.getSavedQuery(stateContainer.getState().savedQuery).then(savedQuery => {
$scope.$evalAsync(() => {
$scope.savedQuery = savedQuery;
});
});
}

$scope.$watch('savedQuery', newSavedQuery => {
if (!newSavedQuery) return;
stateContainer.transitions.set('savedQuery', newSavedQuery.id);

updateStateFromSavedQuery(newSavedQuery);
});
$scope.updateSavedQuery = savedQuery => {
$scope.savedQuery = savedQuery;
updateStateFromSavedQuery(savedQuery);
};

$scope.$watch('linked', linked => {
if (linked && !savedVis.savedSearchId) {
Expand Down Expand Up @@ -626,7 +632,10 @@ function VisualizeAppController(
savedVis.vis.title = savedVis.title;
savedVis.vis.description = savedVis.description;
} else {
kbnUrl.change(`${VisualizeConstants.EDIT_PATH}/{{id}}`, { id: savedVis.id });
history.replace({
...history.location,
pathname: `${VisualizeConstants.EDIT_PATH}/${savedVis.id}`,
});
}
}
});
Expand Down
Loading

0 comments on commit adb65a7

Please sign in to comment.