Skip to content

Commit adb65a7

Browse files
[Visualize] Remove global state in visualize (#58352) (#59636)
* 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>
1 parent 5f06b79 commit adb65a7

File tree

10 files changed

+118
-201
lines changed

10 files changed

+118
-201
lines changed

src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,8 @@
2424
* directly where they are needed.
2525
*/
2626

27-
export { State } from 'ui/state_management/state';
28-
// @ts-ignore
29-
export { GlobalStateProvider } from 'ui/state_management/global_state';
30-
// @ts-ignore
31-
export { StateManagementConfigProvider } from 'ui/state_management/config_provider';
32-
3327
export { subscribeWithScope } from 'ui/utils/subscribe_with_scope';
3428
// @ts-ignore
35-
export { EventsProvider } from 'ui/events';
36-
export { registerTimefilterWithGlobalStateFactory } from 'ui/timefilter/setup_router';
37-
// @ts-ignore
3829
export { KbnUrlProvider, RedirectWhenMissingProvider } from 'ui/url';
3930
export { absoluteToParsedUrl } from 'ui/url/absolute_to_parsed_url';
4031
export { KibanaParsedUrl } from 'ui/url/kibana_parsed_url';

src/legacy/core_plugins/kibana/public/visualize/np_ready/application.ts

Lines changed: 2 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,11 @@ import { i18nDirective, i18nFilter, I18nProvider } from '@kbn/i18n/angular';
2323
import { AppMountContext } from 'kibana/public';
2424
import {
2525
configureAppAngularModule,
26-
GlobalStateProvider,
2726
KbnUrlProvider,
2827
RedirectWhenMissingProvider,
2928
IPrivate,
3029
PrivateProvider,
3130
PromiseServiceCreator,
32-
StateManagementConfigProvider,
3331
} from '../legacy_imports';
3432
import { NavigationPublicPluginStart as NavigationStart } from '../../../../../../plugins/navigation/public';
3533
import {
@@ -87,55 +85,27 @@ function createLocalAngularModule(core: AppMountContext['core'], navigation: Nav
8785
createLocalI18nModule();
8886
createLocalPrivateModule();
8987
createLocalPromiseModule();
90-
createLocalConfigModule(core);
9188
createLocalKbnUrlModule();
92-
createLocalStateModule();
9389
createLocalTopNavModule(navigation);
9490

9591
const visualizeAngularModule: IModule = angular.module(moduleName, [
9692
...thirdPartyAngularDependencies,
97-
'app/visualize/Config',
9893
'app/visualize/I18n',
9994
'app/visualize/Private',
10095
'app/visualize/TopNav',
101-
'app/visualize/State',
96+
'app/visualize/KbnUrl',
97+
'app/visualize/Promise',
10298
]);
10399
return visualizeAngularModule;
104100
}
105101

106-
function createLocalStateModule() {
107-
angular
108-
.module('app/visualize/State', [
109-
'app/visualize/Private',
110-
'app/visualize/Config',
111-
'app/visualize/KbnUrl',
112-
'app/visualize/Promise',
113-
])
114-
.service('globalState', function(Private: IPrivate) {
115-
return Private(GlobalStateProvider);
116-
});
117-
}
118-
119102
function createLocalKbnUrlModule() {
120103
angular
121104
.module('app/visualize/KbnUrl', ['app/visualize/Private', 'ngRoute'])
122105
.service('kbnUrl', (Private: IPrivate) => Private(KbnUrlProvider))
123106
.service('redirectWhenMissing', (Private: IPrivate) => Private(RedirectWhenMissingProvider));
124107
}
125108

126-
function createLocalConfigModule(core: AppMountContext['core']) {
127-
angular
128-
.module('app/visualize/Config', ['app/visualize/Private'])
129-
.provider('stateManagementConfig', StateManagementConfigProvider)
130-
.provider('config', () => {
131-
return {
132-
$get: () => ({
133-
get: core.uiSettings.get.bind(core.uiSettings),
134-
}),
135-
};
136-
});
137-
}
138-
139109
function createLocalPromiseModule() {
140110
angular.module('app/visualize/Promise', []).service('Promise', PromiseServiceCreator);
141111
}

src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/editor.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@
3131
refresh-interval="refreshInterval.value"
3232
on-refresh-change="onRefreshChange"
3333
show-save-query="showSaveQuery"
34-
on-saved="onQuerySaved"
35-
on-saved-query-updated="onSavedQueryUpdated"
34+
on-saved="updateSavedQuery"
35+
on-saved-query-updated="updateSavedQuery"
3636
on-clear-saved-query="onClearSavedQuery"
3737
>
3838
</kbn-top-nav>

src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/editor.js

Lines changed: 67 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import angular from 'angular';
2121
import _ from 'lodash';
2222
import { Subscription } from 'rxjs';
23+
import { map } from 'rxjs/operators';
2324
import { i18n } from '@kbn/i18n';
2425

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

3132
import { addHelpMenuToAppChrome } from '../help_menu/help_menu_util';
32-
import { FilterStateManager } from '../../../../../data/public';
3333
import { unhashUrl } from '../../../../../../../plugins/kibana_utils/public';
3434
import { kbnBaseUrl } from '../../../../../../../plugins/kibana_legacy/public';
3535
import {
3636
SavedObjectSaveModal,
3737
showSaveModal,
3838
} from '../../../../../../../plugins/saved_objects/public';
39+
import {
40+
esFilters,
41+
connectToQueryState,
42+
syncQueryStateWithUrl,
43+
} from '../../../../../../../plugins/data/public';
3944

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

6671
function VisualizeAppController(
6772
$scope,
68-
$element,
6973
$route,
7074
$window,
7175
$injector,
7276
$timeout,
7377
kbnUrl,
7478
redirectWhenMissing,
75-
Promise,
76-
globalState,
77-
config
79+
kbnUrlStateStorage,
80+
history
7881
) {
7982
const {
8083
indexPatterns,
8184
localStorage,
8285
visualizeCapabilities,
8386
share,
84-
data: {
85-
query: {
86-
filterManager,
87-
timefilter: { timefilter },
88-
},
89-
},
87+
data: { query: queryService },
9088
toastNotifications,
9189
chrome,
9290
getBasePath,
@@ -97,6 +95,17 @@ function VisualizeAppController(
9795
setActiveUrl,
9896
} = getServices();
9997

98+
const {
99+
filterManager,
100+
timefilter: { timefilter },
101+
} = queryService;
102+
103+
// starts syncing `_g` portion of url with query services
104+
const { stop: stopSyncingQueryServiceStateWithUrl } = syncQueryStateWithUrl(
105+
queryService,
106+
kbnUrlStateStorage
107+
);
108+
100109
// Retrieve the resolved SavedVis instance.
101110
const savedVis = $route.current.locals.savedVis;
102111
const _applyVis = () => {
@@ -284,26 +293,24 @@ function VisualizeAppController(
284293
linked: !!savedVis.savedSearchId,
285294
};
286295

287-
const useHash = config.get('state:storeInSessionStorage');
288296
const { stateContainer, stopStateSync } = useVisualizeAppState({
289-
useHash,
290297
stateDefaults,
298+
kbnUrlStateStorage,
291299
});
292300

293-
const filterStateManager = new FilterStateManager(
294-
globalState,
295-
() => {
296-
// Temporary AppState replacement
297-
return {
298-
set filters(_filters) {
299-
stateContainer.transitions.set('filters', _filters);
300-
},
301-
get filters() {
302-
return stateContainer.getState().filters;
303-
},
304-
};
301+
// sync initial app filters from state to filterManager
302+
filterManager.setAppFilters(_.cloneDeep(stateContainer.getState().filters));
303+
// setup syncing of app filters between appState and filterManager
304+
const stopSyncingAppFilters = connectToQueryState(
305+
queryService,
306+
{
307+
set: ({ filters }) => stateContainer.transitions.set('filters', filters),
308+
get: () => ({ filters: stateContainer.getState().filters }),
309+
state$: stateContainer.state$.pipe(map(state => ({ filters: state.filters }))),
305310
},
306-
filterManager
311+
{
312+
filters: esFilters.FilterStateStore.APP_STATE,
313+
}
307314
);
308315

309316
// The savedVis is pulled from elasticsearch, but the appState is pulled from the url, with the
@@ -335,6 +342,24 @@ function VisualizeAppController(
335342
}
336343
);
337344

345+
const updateSavedQueryFromUrl = savedQueryId => {
346+
if (!savedQueryId) {
347+
delete $scope.savedQuery;
348+
349+
return;
350+
}
351+
352+
if ($scope.savedQuery && $scope.savedQuery.id === savedQueryId) {
353+
return;
354+
}
355+
356+
savedQueryService.getSavedQuery(savedQueryId).then(savedQuery => {
357+
$scope.$evalAsync(() => {
358+
$scope.updateSavedQuery(savedQuery);
359+
});
360+
});
361+
};
362+
338363
function init() {
339364
if (vis.indexPattern) {
340365
$scope.indexPattern = vis.indexPattern;
@@ -388,14 +413,14 @@ function VisualizeAppController(
388413
};
389414

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

393417
const unsubscribeStateUpdates = stateContainer.subscribe(state => {
394418
const newQuery = migrateLegacyQuery(state.query);
395419
if (!_.isEqual(state.query, newQuery)) {
396420
stateContainer.transitions.set('query', newQuery);
397421
}
398422
persistOnChange(state);
423+
updateSavedQueryFromUrl(state.savedQuery);
399424

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

441+
// update the query if savedQuery is stored
442+
updateSavedQueryFromUrl(initialState.savedQuery);
443+
416444
const subscriptions = new Subscription();
417445

418446
subscriptions.add(
@@ -438,7 +466,7 @@ function VisualizeAppController(
438466

439467
// update the searchSource when query updates
440468
$scope.fetch = function() {
441-
const { query, filters, linked } = stateContainer.getState();
469+
const { query, linked, filters } = stateContainer.getState();
442470
$scope.query = query;
443471
$scope.linked = linked;
444472
savedVis.searchSource.setField('query', query);
@@ -451,7 +479,6 @@ function VisualizeAppController(
451479
subscribeWithScope($scope, filterManager.getUpdates$(), {
452480
next: () => {
453481
$scope.filters = filterManager.getFilters();
454-
$scope.globalFilters = filterManager.getGlobalFilters();
455482
},
456483
})
457484
);
@@ -466,13 +493,14 @@ function VisualizeAppController(
466493
$scope._handler.destroy();
467494
}
468495
savedVis.destroy();
469-
filterStateManager.destroy();
470496
subscriptions.unsubscribe();
471497
$scope.vis.off('apply', _applyVis);
472498

473499
unsubscribePersisted();
474500
unsubscribeStateUpdates();
475501
stopStateSync();
502+
stopSyncingQueryServiceStateWithUrl();
503+
stopSyncingAppFilters();
476504
});
477505

478506
$timeout(() => {
@@ -501,23 +529,14 @@ function VisualizeAppController(
501529
});
502530
};
503531

504-
$scope.onQuerySaved = savedQuery => {
505-
$scope.savedQuery = savedQuery;
506-
};
507-
508-
$scope.onSavedQueryUpdated = savedQuery => {
509-
$scope.savedQuery = { ...savedQuery };
510-
};
511-
512532
$scope.onClearSavedQuery = () => {
513533
delete $scope.savedQuery;
514534
stateContainer.transitions.removeSavedQuery(defaultQuery);
515535
filterManager.setFilters(filterManager.getGlobalFilters());
516-
$scope.fetch();
517536
};
518537

519538
const updateStateFromSavedQuery = savedQuery => {
520-
stateContainer.transitions.set('query', savedQuery.attributes.query);
539+
stateContainer.transitions.updateFromSavedQuery(savedQuery);
521540

522541
const savedQueryFilters = savedQuery.attributes.filters || [];
523542
const globalFilters = filterManager.getGlobalFilters();
@@ -532,25 +551,12 @@ function VisualizeAppController(
532551
timefilter.setRefreshInterval(savedQuery.attributes.timefilter.refreshInterval);
533552
}
534553
}
535-
536-
$scope.fetch();
537554
};
538555

539-
// update the query if savedQuery is stored
540-
if (stateContainer.getState().savedQuery) {
541-
savedQueryService.getSavedQuery(stateContainer.getState().savedQuery).then(savedQuery => {
542-
$scope.$evalAsync(() => {
543-
$scope.savedQuery = savedQuery;
544-
});
545-
});
546-
}
547-
548-
$scope.$watch('savedQuery', newSavedQuery => {
549-
if (!newSavedQuery) return;
550-
stateContainer.transitions.set('savedQuery', newSavedQuery.id);
551-
552-
updateStateFromSavedQuery(newSavedQuery);
553-
});
556+
$scope.updateSavedQuery = savedQuery => {
557+
$scope.savedQuery = savedQuery;
558+
updateStateFromSavedQuery(savedQuery);
559+
};
554560

555561
$scope.$watch('linked', linked => {
556562
if (linked && !savedVis.savedSearchId) {
@@ -626,7 +632,10 @@ function VisualizeAppController(
626632
savedVis.vis.title = savedVis.title;
627633
savedVis.vis.description = savedVis.description;
628634
} else {
629-
kbnUrl.change(`${VisualizeConstants.EDIT_PATH}/{{id}}`, { id: savedVis.id });
635+
history.replace({
636+
...history.location,
637+
pathname: `${VisualizeConstants.EDIT_PATH}/${savedVis.id}`,
638+
});
630639
}
631640
}
632641
});

0 commit comments

Comments
 (0)