diff --git a/src/legacy/core_plugins/kibana/public/discover/get_inner_angular.ts b/src/legacy/core_plugins/kibana/public/discover/get_inner_angular.ts
index 9c29e182c55d6..76d475c4f7f96 100644
--- a/src/legacy/core_plugins/kibana/public/discover/get_inner_angular.ts
+++ b/src/legacy/core_plugins/kibana/public/discover/get_inner_angular.ts
@@ -22,15 +22,9 @@
// They can stay even after NP cutover
import angular from 'angular';
import { EuiIcon } from '@elastic/eui';
-// @ts-ignore
-import { StateProvider } from 'ui/state_management/state';
import { i18nDirective, i18nFilter, I18nProvider } from '@kbn/i18n/angular';
import { CoreStart, LegacyCoreStart, IUiSettingsClient } from 'kibana/public';
// @ts-ignore
-import { AppStateProvider } from 'ui/state_management/app_state';
-// @ts-ignore
-import { GlobalStateProvider } from 'ui/state_management/global_state';
-// @ts-ignore
import { StateManagementConfigProvider } from 'ui/state_management/config_provider';
// @ts-ignore
import { KbnUrlProvider, RedirectWhenMissingProvider } from 'ui/url';
@@ -117,8 +111,6 @@ export function initializeInnerAngularModule(
createLocalConfigModule(core.uiSettings);
createLocalKbnUrlModule();
createLocalTopNavModule(navigation);
- createLocalGlobalStateModule();
- createLocalAppStateModule();
createLocalStorageModule();
createElasticSearchModule(data);
createPagerFactoryModule();
@@ -136,6 +128,7 @@ export function initializeInnerAngularModule(
'discoverPrivate',
'discoverDocTable',
'discoverPagerFactory',
+ 'discoverPromise',
])
.config(watchMultiDecorator)
.directive('icon', reactDirective => reactDirective(EuiIcon))
@@ -153,9 +146,8 @@ export function initializeInnerAngularModule(
'discoverConfig',
'discoverI18n',
'discoverPrivate',
+ 'discoverPromise',
'discoverTopNav',
- 'discoverGlobalState',
- 'discoverAppState',
'discoverLocalStorageProvider',
'discoverEs',
'discoverDocTable',
@@ -178,19 +170,6 @@ export function initializeInnerAngularModule(
.service('debounce', ['$timeout', DebounceProviderTimeout]);
}
-export function createLocalGlobalStateModule() {
- angular
- .module('discoverGlobalState', [
- 'discoverPrivate',
- 'discoverConfig',
- 'discoverKbnUrl',
- 'discoverPromise',
- ])
- .service('globalState', function(Private: IPrivate) {
- return Private(GlobalStateProvider);
- });
-}
-
function createLocalKbnUrlModule() {
angular
.module('discoverKbnUrl', ['discoverPrivate', 'ngRoute'])
@@ -236,26 +215,6 @@ function createLocalI18nModule() {
.directive('i18nId', i18nDirective);
}
-function createLocalAppStateModule() {
- angular
- .module('discoverAppState', [
- 'discoverGlobalState',
- 'discoverPrivate',
- 'discoverConfig',
- 'discoverKbnUrl',
- 'discoverPromise',
- ])
- .service('AppState', function(Private: IPrivate) {
- return Private(AppStateProvider);
- })
- .service('getAppState', function(Private: any) {
- return Private(AppStateProvider).getAppState;
- })
- .service('State', function(Private: any) {
- return Private(StateProvider);
- });
-}
-
function createLocalStorageModule() {
angular
.module('discoverLocalStorageProvider', ['discoverPrivate'])
@@ -287,7 +246,6 @@ function createDocTableModule() {
.module('discoverDocTable', [
'discoverKbnUrl',
'discoverConfig',
- 'discoverAppState',
'discoverPagerFactory',
'react',
])
diff --git a/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts b/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts
index 7fa5183a4f54b..6947d985be436 100644
--- a/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts
+++ b/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts
@@ -53,14 +53,12 @@ export { wrapInI18nContext } from 'ui/i18n';
export { getRequestInspectorStats, getResponseInspectorStats } from '../../../data/public';
// @ts-ignore
export { intervalOptions } from 'ui/agg_types';
-export { stateMonitorFactory } from 'ui/state_management/state_monitor_factory';
export { subscribeWithScope } from 'ui/utils/subscribe_with_scope';
// @ts-ignore
export { timezoneProvider } from 'ui/vis/lib/timezone';
export { tabifyAggResponse } from '../../../data/public';
export { unhashUrl } from '../../../../../plugins/kibana_utils/public';
export {
- migrateLegacyQuery,
ensureDefaultIndexPattern,
formatMsg,
formatStack,
@@ -80,7 +78,6 @@ export {
SortDirection,
} from '../../../../../plugins/data/public';
export { ElasticSearchHit } from './np_ready/doc_views/doc_views_types';
-export { registerTimefilterWithGlobalStateFactory } from 'ui/timefilter/setup_router';
export { getFormat } from 'ui/visualize/loader/pipeline_helpers/utilities';
// @ts-ignore
export { buildPointSeriesData } from 'ui/agg_response/point_series/point_series';
diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.html b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.html
index 18254aeca5094..2d44b12989228 100644
--- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.html
+++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.html
@@ -5,18 +5,15 @@
{{screenTitle}}
@@ -186,7 +183,6 @@ {{screenTitle}}
columns="state.columns"
infinite-scroll="true"
filter="filterQuery"
- filters="state.filters"
data-shared-item
data-title="{{opts.savedSearch.lastSavedTitle}}"
data-description="{{opts.savedSearch.description}}"
diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js
index 81c10798936f5..cf237d8d79cc2 100644
--- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js
+++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js
@@ -24,17 +24,14 @@ import { debounceTime } from 'rxjs/operators';
import moment from 'moment';
import dateMath from '@elastic/datemath';
import { i18n } from '@kbn/i18n';
-import '../components/field_chooser/field_chooser';
+import { getState, splitState } from './discover_state';
import { RequestAdapter } from '../../../../../../../plugins/inspector/public';
import {
SavedObjectSaveModal,
showSaveModal,
} from '../../../../../../../plugins/saved_objects/public';
-// doc table
-import './doc_table';
-import { getSortArray } from './doc_table/lib/get_sort';
-import { getSortForSearchSource } from './doc_table/lib/get_sort_for_search_source';
+import { getSortArray, getSortForSearchSource } from './doc_table';
import * as columnActions from './doc_table/actions/columns';
import indexTemplate from './discover.html';
@@ -44,26 +41,24 @@ import '../components/fetch_error';
import { getPainlessError } from './get_painless_error';
import { discoverResponseHandler } from './response_handler';
import {
- angular,
getRequestInspectorStats,
getResponseInspectorStats,
getServices,
hasSearchStategyForIndexPattern,
intervalOptions,
- migrateLegacyQuery,
unhashUrl,
- stateMonitorFactory,
subscribeWithScope,
tabifyAggResponse,
getAngularModule,
ensureDefaultIndexPattern,
- registerTimefilterWithGlobalStateFactory,
} from '../../kibana_services';
const {
core,
chrome,
+ data,
docTitle,
+ indexPatterns,
filterManager,
share,
timefilter,
@@ -77,9 +72,11 @@ import {
esFilters,
fieldFormats,
indexPatterns as indexPatternsUtils,
+ connectToQueryState,
+ syncQueryStateWithUrl,
+ getDefaultQuery,
} from '../../../../../../../plugins/data/public';
import { getIndexPatternId } from '../helpers/get_index_pattern_id';
-import { FilterStateManager } from '../../../../../data/public';
const fetchStatuses = {
UNINITIALIZED: 'uninitialized',
@@ -88,9 +85,6 @@ const fetchStatuses = {
};
const app = getAngularModule();
-app.run((globalState, $rootScope) => {
- registerTimefilterWithGlobalStateFactory(timefilter, globalState, $rootScope);
-});
app.config($routeProvider => {
const defaults = {
@@ -119,10 +113,11 @@ app.config($routeProvider => {
template: indexTemplate,
reloadOnSearch: false,
resolve: {
- savedObjects: function(redirectWhenMissing, $route, kbnUrl, Promise, $rootScope, State) {
- const indexPatterns = getServices().indexPatterns;
+ savedObjects: function(redirectWhenMissing, $route, kbnUrl, Promise, $rootScope) {
const savedSearchId = $route.current.params.id;
- return ensureDefaultIndexPattern(core, getServices().data, $rootScope, kbnUrl).then(() => {
+ return ensureDefaultIndexPattern(core, data, $rootScope, kbnUrl).then(() => {
+ const { appStateContainer } = getState({});
+ const { index } = appStateContainer.getState();
return Promise.props({
ip: indexPatterns.getCache().then(indexPatternList => {
/**
@@ -134,22 +129,16 @@ app.config($routeProvider => {
*
* @type {State}
*/
- const state = new State('_a', {});
- const id = getIndexPatternId(
- state.index,
- indexPatternList,
- uiSettings.get('defaultIndex')
- );
- state.destroy();
+ const id = getIndexPatternId(index, indexPatternList, uiSettings.get('defaultIndex'));
return Promise.props({
list: indexPatternList,
loaded: indexPatterns.get(id),
- stateVal: state.index,
- stateValFound: !!state.index && id === state.index,
+ stateVal: index,
+ stateValFound: !!index && id === index,
});
}),
savedSearch: getServices()
- .getSavedSearchById(savedSearchId, kbnUrl)
+ .getSavedSearchById(savedSearchId)
.then(savedSearch => {
if (savedSearchId) {
chrome.recentlyAccessed.add(
@@ -188,23 +177,114 @@ function discoverController(
$scope,
$timeout,
$window,
- AppState,
Promise,
config,
kbnUrl,
localStorage,
- uiCapabilities,
- getAppState,
- globalState
+ uiCapabilities
) {
- const filterStateManager = new FilterStateManager(globalState, getAppState, filterManager);
+ const { isDefault: isDefaultType } = indexPatternsUtils;
+ const subscriptions = new Subscription();
+ const $fetchObservable = new Subject();
+ let inspectorRequest;
+ const savedSearch = $route.current.locals.savedObjects.savedSearch;
+ $scope.searchSource = savedSearch.searchSource;
+ $scope.indexPattern = resolveIndexPatternLoading();
+
+ const getTimeField = () => {
+ return isDefaultType($scope.indexPattern) ? $scope.indexPattern.timeFieldName : undefined;
+ };
+
+ const {
+ appStateContainer,
+ startSync: startStateSync,
+ stopSync: stopStateSync,
+ setAppState,
+ replaceUrlAppState,
+ isAppStateDirty,
+ kbnUrlStateStorage,
+ getPreviousAppState,
+ } = getState({
+ defaultAppState: getStateDefaults(),
+ storeInSessionStorage: config.get('state:storeInSessionStorage'),
+ });
+ if (appStateContainer.getState().index !== $scope.indexPattern.id) {
+ //used index pattern is different than the given by url/state which is invalid
+ setAppState({ index: $scope.indexPattern.id });
+ }
+ $scope.state = { ...appStateContainer.getState() };
+
+ // syncs `_g` portion of url with query services
+ const { stop: stopSyncingGlobalStateWithUrl } = syncQueryStateWithUrl(
+ data.query,
+ kbnUrlStateStorage
+ );
+
+ // sync initial app filters from state to filterManager
+ filterManager.setAppFilters(_.cloneDeep(appStateContainer.getState().filters));
+
+ const stopSyncingQueryAppStateWithStateContainer = connectToQueryState(
+ data.query,
+ appStateContainer,
+ { filters: esFilters.FilterStateStore.APP_STATE }
+ );
+
+ const appStateUnsubscribe = appStateContainer.subscribe(async newState => {
+ const { state: newStatePartial } = splitState(newState);
+ const { state: oldStatePartial } = splitState(getPreviousAppState());
+
+ if (!_.isEqual(newStatePartial, oldStatePartial)) {
+ $scope.$evalAsync(async () => {
+ $scope.state = { ...newState };
+
+ // detect changes that should trigger fetching of new data
+ const changes = ['interval', 'sort', 'index', 'query'].filter(
+ prop => !_.isEqual(newStatePartial[prop], oldStatePartial[prop])
+ );
+ if (changes.indexOf('index') !== -1) {
+ try {
+ $scope.indexPattern = await indexPatterns.get(newStatePartial.index);
+ $scope.opts.timefield = getTimeField();
+ $scope.enableTimeRangeSelector = !!$scope.opts.timefield;
+ // is needed to rerender the histogram
+ $scope.vis = undefined;
+
+ // Taking care of sort when switching index pattern:
+ // Old indexPattern: sort by A
+ // If A is not available in the new index pattern, sort has to be adapted and propagated to URL
+ const sort = getSortArray(newStatePartial.sort, $scope.indexPattern);
+ if (newStatePartial.sort && !_.isEqual(sort, newStatePartial.sort)) {
+ return await replaceUrlAppState({ sort });
+ }
+ } catch (e) {
+ toastNotifications.addWarning({ text: getIndexPatternWarning(newStatePartial.index) });
+ }
+ }
+
+ if (changes.length) {
+ $fetchObservable.next();
+ }
+ });
+ }
+ });
+
+ $scope.setIndexPattern = id => {
+ setAppState({ index: id });
+ };
+
+ // update data source when filters update
+ subscriptions.add(
+ subscribeWithScope($scope, filterManager.getUpdates$(), {
+ next: () => {
+ $scope.updateDataSource();
+ },
+ })
+ );
const inspectorAdapters = {
requests: new RequestAdapter(),
};
- const subscriptions = new Subscription();
-
$scope.timefilterUpdateHandler = ranges => {
timefilter.setTime({
from: moment(ranges.from).toISOString(),
@@ -213,7 +293,6 @@ function discoverController(
});
};
$scope.intervalOptions = intervalOptions;
- $scope.showInterval = false;
$scope.minimumVisibleRows = 50;
$scope.fetchStatus = fetchStatuses.UNINITIALIZED;
$scope.showSaveQuery = uiCapabilities.discover.saveQuery;
@@ -229,19 +308,15 @@ function discoverController(
return interval.val !== 'custom';
};
- // the saved savedSearch
- const savedSearch = $route.current.locals.savedObjects.savedSearch;
-
let abortController;
$scope.$on('$destroy', () => {
if (abortController) abortController.abort();
savedSearch.destroy();
subscriptions.unsubscribe();
- filterStateManager.destroy();
- });
-
- const $appStatus = ($scope.appStatus = this.appStatus = {
- dirty: !savedSearch.id,
+ appStateUnsubscribe();
+ stopStateSync();
+ stopSyncingGlobalStateWithUrl();
+ stopSyncingQueryAppStateWithStateContainer();
});
const getTopNavLinks = () => {
@@ -299,7 +374,7 @@ function discoverController(
onSave={onSave}
onClose={() => {}}
title={savedSearch.title}
- showCopyOnSave={savedSearch.id ? true : false}
+ showCopyOnSave={!!savedSearch.id}
objectType="search"
description={i18n.translate('kbn.discover.localMenu.saveSaveSearchDescription', {
defaultMessage:
@@ -353,7 +428,7 @@ function discoverController(
...sharingData,
title: savedSearch.title,
},
- isDirty: $appStatus.dirty,
+ isDirty: !savedSearch.id || isAppStateDirty(),
});
},
};
@@ -382,13 +457,8 @@ function discoverController(
inspectSearch,
];
};
-
$scope.topNavMenu = getTopNavLinks();
- // the actual courier.SearchSource
- $scope.searchSource = savedSearch.searchSource;
- $scope.indexPattern = resolveIndexPatternLoading();
-
$scope.searchSource
.setField('index', $scope.indexPattern)
.setField('highlightAll', true)
@@ -401,7 +471,7 @@ function discoverController(
// searchSource which applies time range
const timeRangeSearchSource = savedSearch.searchSource.create();
- if (indexPatternsUtils.isDefault($scope.indexPattern)) {
+ if (isDefaultType($scope.indexPattern)) {
timeRangeSearchSource.setField('filter', () => {
return timefilter.createFilter($scope.indexPattern);
});
@@ -431,11 +501,6 @@ function discoverController(
]);
}
- let stateMonitor;
-
- const $state = ($scope.state = new AppState(getStateDefaults()));
- const $fetchObservable = new Subject();
-
$scope.screenTitle = savedSearch.title;
const getFieldCounts = async () => {
@@ -455,8 +520,7 @@ function discoverController(
});
};
- const getSharingDataFields = async () => {
- const selectedFields = $state.columns;
+ const getSharingDataFields = async (selectedFields, timeFieldName, hideTimeColumn) => {
if (selectedFields.length === 1 && selectedFields[0] === '_source') {
const fieldCounts = await getFieldCounts();
return {
@@ -465,8 +529,6 @@ function discoverController(
};
}
- const timeFieldName = $scope.indexPattern.timeFieldName;
- const hideTimeColumn = config.get('doc_table:hideTimeColumn');
const fields =
timeFieldName && !hideTimeColumn ? [timeFieldName, ...selectedFields] : selectedFields;
return {
@@ -478,12 +540,16 @@ function discoverController(
this.getSharingData = async () => {
const searchSource = $scope.searchSource.createCopy();
- const { searchFields, selectFields } = await getSharingDataFields();
+ const { searchFields, selectFields } = await getSharingDataFields(
+ $scope.state.columns,
+ $scope.indexPattern.timeFieldName,
+ config.get('doc_table:hideTimeColumn')
+ );
searchSource.setField('fields', searchFields);
searchSource.setField(
'sort',
getSortForSearchSource(
- $state.sort,
+ $scope.state.sort,
$scope.indexPattern,
config.get('discover:sort:defaultOrder')
)
@@ -508,29 +574,25 @@ function discoverController(
};
};
- $scope.uiState = $state.makeStateful('uiState');
-
function getStateDefaults() {
+ const query =
+ $scope.searchSource.getField('query') ||
+ getDefaultQuery(
+ localStorage.get('kibana.userQueryLanguage') || config.get('search:queryLanguage')
+ );
return {
- query: ($scope.savedQuery && $scope.savedQuery.attributes.query) ||
- $scope.searchSource.getField('query') || {
- query: '',
- language:
- localStorage.get('kibana.userQueryLanguage') || config.get('search:queryLanguage'),
- },
+ query,
sort: getSortArray(savedSearch.sort, $scope.indexPattern),
columns:
savedSearch.columns.length > 0 ? savedSearch.columns : config.get('defaultColumns').slice(),
index: $scope.indexPattern.id,
interval: 'auto',
- filters:
- ($scope.savedQuery && $scope.savedQuery.attributes.filters) ||
- _.cloneDeep($scope.searchSource.getOwnField('filter')),
+ filters: _.cloneDeep($scope.searchSource.getOwnField('filter')),
};
}
- $state.index = $scope.indexPattern.id;
- $state.sort = getSortArray($state.sort, $scope.indexPattern);
+ $scope.state.index = $scope.indexPattern.id;
+ $scope.state.sort = getSortArray($scope.state.sort, $scope.indexPattern);
$scope.getBucketIntervalToolTipText = () => {
return i18n.translate('kbn.discover.bucketIntervalTooltip', {
@@ -550,16 +612,10 @@ function discoverController(
});
};
- $scope.$watchCollection('state.columns', function() {
- $state.save();
- });
-
$scope.opts = {
// number of records to fetch, then paginate through
sampleSize: config.get('discover:sampleSize'),
- timefield: indexPatternsUtils.isDefault($scope.indexPattern)
- ? $scope.indexPattern.timeFieldName
- : undefined,
+ timefield: getTimeField(),
savedSearch: savedSearch,
indexPatternList: $route.current.locals.savedObjects.ip.list,
};
@@ -574,14 +630,8 @@ function discoverController(
);
};
- const init = _.once(function() {
- stateMonitor = stateMonitorFactory.create($state, getStateDefaults());
- stateMonitor.onChange(status => {
- $appStatus.dirty = status.dirty || !savedSearch.id;
- });
- $scope.$on('$destroy', () => stateMonitor.destroy());
-
- $scope.updateDataSource().then(function() {
+ const init = _.once(() => {
+ $scope.updateDataSource().then(async () => {
const searchBarChanges = merge(
timefilter.getAutoRefreshFetch$(),
timefilter.getFetch$(),
@@ -601,47 +651,16 @@ function discoverController(
},
})
);
-
- $scope.$watchCollection('state.sort', function(sort) {
- if (!sort) return;
-
- // get the current sort from searchSource as array of arrays
- const currentSort = getSortArray($scope.searchSource.getField('sort'), $scope.indexPattern);
-
- // if the searchSource doesn't know, tell it so
- if (!angular.equals(sort, currentSort)) $fetchObservable.next();
- });
-
- // update data source when filters update
-
- subscriptions.add(
- subscribeWithScope($scope, filterManager.getUpdates$(), {
- next: () => {
- $scope.updateDataSource().then(function() {
- $state.save();
- });
- },
- })
- );
-
- // update data source when hitting forward/back and the query changes
- $scope.$listen($state, 'fetch_with_changes', function(diff) {
- if (diff.indexOf('query') >= 0) $fetchObservable.next();
- });
-
- $scope.$watch('opts.timefield', function(timefield) {
- $scope.enableTimeRangeSelector = !!timefield;
- });
-
+ //Handling change oft the histogram interval
$scope.$watch('state.interval', function(newInterval, oldInterval) {
if (newInterval !== oldInterval) {
- $fetchObservable.next();
+ setAppState({ interval: newInterval });
}
});
$scope.$watch('vis.aggs', function() {
// no timefield, no vis, nothing to update
- if (!$scope.opts.timefield) return;
+ if (!getTimeField() || !$scope.vis) return;
const buckets = $scope.vis.getAggConfig().byTypeName('buckets');
@@ -650,15 +669,6 @@ function discoverController(
}
});
- $scope.$watch('state.query', (newQuery, oldQuery) => {
- if (!_.isEqual(newQuery, oldQuery)) {
- const query = migrateLegacyQuery(newQuery);
- if (!_.isEqual(query, newQuery)) {
- $scope.updateQuery({ query });
- }
- }
- });
-
$scope.$watchMulti(
['rows', 'fetchStatus'],
(function updateResultState() {
@@ -705,14 +715,12 @@ function discoverController(
})()
);
- if ($scope.opts.timefield) {
+ if (getTimeField()) {
setupVisualization();
$scope.updateTime();
}
init.complete = true;
- $state.replace();
-
if (shouldSearchOnPageLoad()) {
$fetchObservable.next();
}
@@ -728,7 +736,6 @@ function discoverController(
try {
const id = await savedSearch.save(saveOptions);
$scope.$evalAsync(() => {
- stateMonitor.setInitialState($state.toJSON());
if (id) {
toastNotifications.addSuccess({
title: i18n.translate('kbn.discover.notifications.savedSearchTitle', {
@@ -744,7 +751,7 @@ function discoverController(
kbnUrl.change('/discover/{{id}}', { id: savedSearch.id });
} else {
// Update defaults so that "reload saved query" functions correctly
- $state.setDefaults(getStateDefaults());
+ setAppState(getStateDefaults());
docTitle.change(savedSearch.lastSavedTitle);
}
}
@@ -770,8 +777,6 @@ function discoverController(
$scope.fetchError = undefined;
- $scope.updateTime();
-
// Abort any in-progress requests before fetching again
if (abortController) abortController.abort();
abortController = new AbortController();
@@ -780,7 +785,6 @@ function discoverController(
.updateDataSource()
.then(setupVisualization)
.then(function() {
- $state.save();
$scope.fetchStatus = fetchStatuses.LOADING;
logInspectorRequest();
return $scope.searchSource.fetch({
@@ -808,10 +812,27 @@ function discoverController(
};
$scope.updateQuery = function({ query }) {
- $state.query = query;
+ setAppState({ query });
$fetchObservable.next();
};
+ $scope.updateSavedQueryId = newSavedQueryId => {
+ if (newSavedQueryId) {
+ setAppState({ savedQuery: newSavedQueryId });
+ } else {
+ //reset filters and query string, remove savedQuery from state
+ const state = {
+ ...appStateContainer.getState(),
+ query: getDefaultQuery(
+ localStorage.get('kibana.userQueryLanguage') || config.get('search:queryLanguage')
+ ),
+ filters: [],
+ };
+ delete state.savedQuery;
+ appStateContainer.set(state);
+ }
+ };
+
function getDimensions(aggs, timeRange) {
const [metric, agg] = aggs;
agg.params.timeRange = timeRange;
@@ -842,9 +863,9 @@ function discoverController(
}
function onResults(resp) {
- logInspectorResponse(resp);
+ inspectorRequest.stats(getResponseInspectorStats($scope.searchSource, resp)).ok({ json: resp });
- if ($scope.opts.timefield) {
+ if (getTimeField()) {
const tabifiedData = tabifyAggResponse($scope.vis.aggs, resp);
$scope.searchSource.rawResponse = resp;
$scope.histogramData = discoverResponseHandler(
@@ -869,8 +890,6 @@ function discoverController(
$scope.fetchStatus = fetchStatuses.COMPLETE;
}
- let inspectorRequest;
-
function logInspectorRequest() {
inspectorAdapters.requests.reset();
const title = i18n.translate('kbn.discover.inspectorRequestDataTitle', {
@@ -886,11 +905,8 @@ function discoverController(
});
}
- function logInspectorResponse(resp) {
- inspectorRequest.stats(getResponseInspectorStats($scope.searchSource, resp)).ok({ json: resp });
- }
-
$scope.updateTime = function() {
+ //this is the timerange for the histogram, should be refactored
$scope.timeRange = {
from: dateMath.parse(timefilter.getTime().from),
to: dateMath.parse(timefilter.getTime().to, { roundUp: true }),
@@ -909,20 +925,26 @@ function discoverController(
kbnUrl.change('/discover');
};
- $scope.updateDataSource = Promise.method(function updateDataSource() {
+ $scope.updateDataSource = () => {
const { indexPattern, searchSource } = $scope;
searchSource
+ .setField('index', $scope.indexPattern)
.setField('size', $scope.opts.sampleSize)
.setField(
'sort',
- getSortForSearchSource($state.sort, indexPattern, config.get('discover:sort:defaultOrder'))
+ getSortForSearchSource(
+ $scope.state.sort,
+ indexPattern,
+ config.get('discover:sort:defaultOrder')
+ )
)
- .setField('query', !$state.query ? null : $state.query)
+ .setField('query', $scope.state.query || null)
.setField('filter', filterManager.getFilters());
- });
+ return Promise.resolve();
+ };
- $scope.setSortOrder = function setSortOrder(sortPair) {
- $scope.state.sort = sortPair;
+ $scope.setSortOrder = function setSortOrder(sort) {
+ setAppState({ sort });
};
// TODO: On array fields, negating does not negate the combination, rather all terms
@@ -940,16 +962,19 @@ function discoverController(
$scope.addColumn = function addColumn(columnName) {
$scope.indexPattern.popularizeField(columnName, 1);
- columnActions.addColumn($scope.state.columns, columnName);
+ const columns = columnActions.addColumn($scope.state.columns, columnName);
+ setAppState({ columns });
};
$scope.removeColumn = function removeColumn(columnName) {
$scope.indexPattern.popularizeField(columnName, 1);
- columnActions.removeColumn($scope.state.columns, columnName);
+ const columns = columnActions.removeColumn($scope.state.columns, columnName);
+ setAppState({ columns });
};
$scope.moveColumn = function moveColumn(columnName, newIndex) {
- columnActions.moveColumn($scope.state.columns, columnName, newIndex);
+ const columns = columnActions.moveColumn($scope.state.columns, columnName, newIndex);
+ setAppState({ columns });
};
$scope.scrollToTop = function() {
@@ -967,18 +992,10 @@ function discoverController(
$scope.minimumVisibleRows = $scope.hits;
};
- $scope.updateSavedQueryId = newSavedQueryId => {
- if (newSavedQueryId) {
- $state.savedQuery = newSavedQueryId;
- } else {
- delete $state.savedQuery;
- }
- $state.save();
- };
-
async function setupVisualization() {
// If no timefield has been specified we don't create a histogram of messages
- if (!$scope.opts.timefield) return;
+ if (!getTimeField()) return;
+ const { interval: histogramInterval } = $scope.state;
const visStateAggs = [
{
@@ -989,8 +1006,8 @@ function discoverController(
type: 'date_histogram',
schema: 'segment',
params: {
- field: $scope.opts.timefield,
- interval: $state.interval,
+ field: getTimeField(),
+ interval: histogramInterval,
timeRange: timefilter.getTime(),
},
},
@@ -1024,14 +1041,25 @@ function discoverController(
visSavedObject.vis = $scope.vis;
$scope.searchSource.onRequestStart((searchSource, options) => {
+ if (!$scope.vis) return;
return $scope.vis.getAggConfig().onSearchRequestStart(searchSource, options);
});
$scope.searchSource.setField('aggs', function() {
+ if (!$scope.vis) return;
return $scope.vis.getAggConfig().toDsl();
});
}
+ function getIndexPatternWarning(index) {
+ return i18n.translate('kbn.discover.valueIsNotConfiguredIndexPatternIDWarningTitle', {
+ defaultMessage: '{stateVal} is not a configured index pattern ID',
+ values: {
+ stateVal: `"${index}"`,
+ },
+ });
+ }
+
function resolveIndexPatternLoading() {
const {
loaded: loadedIndexPattern,
@@ -1046,15 +1074,7 @@ function discoverController(
}
if (stateVal && !stateValFound) {
- const warningTitle = i18n.translate(
- 'kbn.discover.valueIsNotConfiguredIndexPatternIDWarningTitle',
- {
- defaultMessage: '{stateVal} is not a configured index pattern ID',
- values: {
- stateVal: `"${stateVal}"`,
- },
- }
- );
+ const warningTitle = getIndexPatternWarning();
if (ownIndexPattern) {
toastNotifications.addWarning({
@@ -1090,7 +1110,7 @@ function discoverController(
// Block the UI from loading if the user has loaded a rollup index pattern but it isn't
// supported.
$scope.isUnsupportedIndexPattern =
- !indexPatternsUtils.isDefault($route.current.locals.savedObjects.ip.loaded) &&
+ !isDefaultType($route.current.locals.savedObjects.ip.loaded) &&
!hasSearchStategyForIndexPattern($route.current.locals.savedObjects.ip.loaded);
if ($scope.isUnsupportedIndexPattern) {
@@ -1101,4 +1121,6 @@ function discoverController(
addHelpMenuToAppChrome(chrome);
init();
+ // Propagate current app state to url, then start syncing
+ replaceUrlAppState().then(() => startStateSync());
}
diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover_state.test.ts b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover_state.test.ts
new file mode 100644
index 0000000000000..af772cb5c76f1
--- /dev/null
+++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover_state.test.ts
@@ -0,0 +1,78 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { getState, GetStateReturn } from './discover_state';
+import { createBrowserHistory, History } from 'history';
+
+let history: History;
+let state: GetStateReturn;
+const getCurrentUrl = () => history.createHref(history.location);
+
+describe('Test discover state', () => {
+ beforeEach(async () => {
+ history = createBrowserHistory();
+ history.push('/');
+ state = getState({
+ defaultAppState: { index: 'test' },
+ hashHistory: history,
+ });
+ await state.replaceUrlAppState({});
+ await state.startSync();
+ });
+ afterEach(() => {
+ state.stopSync();
+ });
+ test('setting app state and syncing to URL', async () => {
+ state.setAppState({ index: 'modified' });
+ state.flushToUrl();
+ expect(getCurrentUrl()).toMatchInlineSnapshot(`"/#?_a=(index:modified)"`);
+ });
+
+ test('changing URL to be propagated to appState', async () => {
+ history.push('/#?_a=(index:modified)');
+ expect(state.appStateContainer.getState()).toMatchInlineSnapshot(`
+ Object {
+ "index": "modified",
+ }
+ `);
+ });
+ test('URL navigation to url without _a, state should not change', async () => {
+ history.push('/#?_a=(index:modified)');
+ history.push('/');
+ expect(state.appStateContainer.getState()).toMatchInlineSnapshot(`
+ Object {
+ "index": "modified",
+ }
+ `);
+ });
+
+ test('isAppStateDirty returns whether the current state has changed', async () => {
+ state.setAppState({ index: 'modified' });
+ expect(state.isAppStateDirty()).toBeTruthy();
+ state.resetInitialAppState();
+ expect(state.isAppStateDirty()).toBeFalsy();
+ });
+
+ test('getPreviousAppState returns the state before the current', async () => {
+ state.setAppState({ index: 'first' });
+ const stateA = state.appStateContainer.getState();
+ state.setAppState({ index: 'second' });
+ expect(state.getPreviousAppState()).toEqual(stateA);
+ });
+});
diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover_state.ts b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover_state.ts
new file mode 100644
index 0000000000000..10e7cd1d0c49d
--- /dev/null
+++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover_state.ts
@@ -0,0 +1,223 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { isEqual } from 'lodash';
+import { createHashHistory, History } from 'history';
+import {
+ createStateContainer,
+ createKbnUrlStateStorage,
+ syncState,
+ ReduxLikeStateContainer,
+ IKbnUrlStateStorage,
+} from '../../../../../../../plugins/kibana_utils/public';
+import { esFilters, Filter, Query } from '../../../../../../../plugins/data/public';
+import { migrateLegacyQuery } from '../../../../../../../plugins/kibana_legacy/public';
+
+interface AppState {
+ /**
+ * Columns displayed in the table
+ */
+ columns?: string[];
+ /**
+ * Array of applied filters
+ */
+ filters?: Filter[];
+ /**
+ * id of the used index pattern
+ */
+ index?: string;
+ /**
+ * Used interval of the histogram
+ */
+ interval?: string;
+ /**
+ * Lucence or KQL query
+ */
+ query?: Query;
+ /**
+ * Array of the used sorting [[field,direction],...]
+ */
+ sort?: string[][];
+}
+
+interface GetStateParams {
+ /**
+ * Default state used for merging with with URL state to get the initial state
+ */
+ defaultAppState?: AppState;
+ /**
+ * Determins the use of long vs. short/hashed urls
+ */
+ storeInSessionStorage?: boolean;
+ /**
+ * Browser history used for testing
+ */
+ hashHistory?: History;
+}
+
+export interface GetStateReturn {
+ /**
+ * kbnUrlStateStorage
+ */
+ kbnUrlStateStorage: IKbnUrlStateStorage;
+ /**
+ * App state, the _a part of the URL
+ */
+ appStateContainer: ReduxLikeStateContainer;
+ /**
+ * Start sync between state and URL
+ */
+ startSync: () => void;
+ /**
+ * Stop sync between state and URL
+ */
+ stopSync: () => void;
+ /**
+ * Set app state to with a partial new app state
+ */
+ setAppState: (newState: Partial) => void;
+ /**
+ * Set state in Url using history.replace
+ */
+ replaceUrlAppState: (newState: Partial) => Promise;
+ /**
+ * Sync state to URL, used for testing
+ */
+ flushToUrl: () => void;
+ /**
+ * Reset initial state to the current app state
+ */
+ resetInitialAppState: () => void;
+ /**
+ * Return the Appstate before the current app state, useful for diffing changes
+ */
+ getPreviousAppState: () => AppState;
+ /**
+ * Returns whether the current app state is different to the initial state
+ */
+ isAppStateDirty: () => void;
+}
+const APP_STATE_URL_KEY = '_a';
+
+/**
+ * Builds and returns appState and globalState containers and helper functions
+ * Used to sync URL with UI state
+ */
+export function getState({
+ defaultAppState = {},
+ storeInSessionStorage = false,
+ hashHistory,
+}: GetStateParams): GetStateReturn {
+ const stateStorage = createKbnUrlStateStorage({
+ useHash: storeInSessionStorage,
+ history: hashHistory ? hashHistory : createHashHistory(),
+ });
+
+ const appStateFromUrl = stateStorage.get(APP_STATE_URL_KEY) as AppState;
+ let initialAppState = {
+ ...defaultAppState,
+ ...appStateFromUrl,
+ };
+ let previousAppState: AppState;
+ const appStateContainer = createStateContainer(initialAppState);
+
+ const appStateContainerModified = {
+ ...appStateContainer,
+ set: (value: AppState | null) => {
+ if (value) {
+ previousAppState = appStateContainer.getState();
+ appStateContainer.set(value);
+ }
+ },
+ };
+
+ const { start, stop } = syncState({
+ storageKey: APP_STATE_URL_KEY,
+ stateContainer: appStateContainerModified,
+ stateStorage,
+ });
+
+ return {
+ kbnUrlStateStorage: stateStorage,
+ appStateContainer: appStateContainerModified,
+ startSync: start,
+ stopSync: stop,
+ setAppState: (newPartial: AppState) => setState(appStateContainerModified, newPartial),
+ replaceUrlAppState: async (newPartial: AppState = {}) => {
+ const state = { ...appStateContainer.getState(), ...newPartial };
+ await stateStorage.set(APP_STATE_URL_KEY, state, { replace: true });
+ },
+ resetInitialAppState: () => {
+ initialAppState = appStateContainer.getState();
+ },
+ getPreviousAppState: () => previousAppState,
+ flushToUrl: () => stateStorage.flush(),
+ isAppStateDirty: () => !isEqualState(initialAppState, appStateContainer.getState()),
+ };
+}
+
+/**
+ * Helper function to merge a given new state with the existing state and to set the given state
+ * container
+ */
+export function setState(stateContainer: ReduxLikeStateContainer, newState: AppState) {
+ const oldState = stateContainer.getState();
+ const mergedState = { ...oldState, ...newState };
+ if (!isEqualState(oldState, mergedState)) {
+ if (mergedState.query) {
+ mergedState.query = migrateLegacyQuery(mergedState.query);
+ }
+ stateContainer.set(mergedState);
+ }
+}
+
+/**
+ * Helper function to compare 2 different filter states
+ */
+export function isEqualFilters(filtersA: Filter[], filtersB: Filter[]) {
+ if (!filtersA && !filtersB) {
+ return true;
+ } else if (!filtersA || !filtersB) {
+ return false;
+ }
+ return esFilters.compareFilters(filtersA, filtersB, esFilters.COMPARE_ALL_OPTIONS);
+}
+
+/**
+ * helper function to extract filters of the given state
+ * returns a state object without filters and an array of filters
+ */
+export function splitState(state: AppState = {}) {
+ const { filters = [], ...statePartial } = state;
+ return { filters, state: statePartial };
+}
+
+/**
+ * Helper function to compare 2 different state, is needed since comparing filters
+ * works differently
+ */
+export function isEqualState(stateA: AppState, stateB: AppState) {
+ if (!stateA && !stateB) {
+ return true;
+ } else if (!stateA || !stateB) {
+ return false;
+ }
+ const { filters: stateAFilters = [], ...stateAPartial } = stateA;
+ const { filters: stateBFilters = [], ...stateBPartial } = stateB;
+ return isEqual(stateAPartial, stateBPartial) && isEqualFilters(stateAFilters, stateBFilters);
+}
diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/actions/columns.ts b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/actions/columns.ts
index ec4fe8025a7c7..cec1a097da5bf 100644
--- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/actions/columns.ts
+++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/actions/columns.ts
@@ -17,35 +17,40 @@
* under the License.
*/
+/**
+ * Helper function to provide a fallback to a single _source column if the given array of columns
+ * is empty, and removes _source if there are more than 1 columns given
+ * @param columns
+ */
+function buildColumns(columns: string[]) {
+ if (columns.length > 1 && columns.indexOf('_source') !== -1) {
+ return columns.filter(col => col !== '_source');
+ } else if (columns.length !== 0) {
+ return columns;
+ }
+ return ['_source'];
+}
+
export function addColumn(columns: string[], columnName: string) {
if (columns.includes(columnName)) {
- return;
+ return columns;
}
-
- columns.push(columnName);
+ return buildColumns([...columns, columnName]);
}
export function removeColumn(columns: string[], columnName: string) {
if (!columns.includes(columnName)) {
- return;
+ return columns;
}
-
- columns.splice(columns.indexOf(columnName), 1);
+ return buildColumns(columns.filter(col => col !== columnName));
}
export function moveColumn(columns: string[], columnName: string, newIndex: number) {
- if (newIndex < 0) {
- return;
+ if (newIndex < 0 || newIndex >= columns.length || !columns.includes(columnName)) {
+ return columns;
}
-
- if (newIndex >= columns.length) {
- return;
- }
-
- if (!columns.includes(columnName)) {
- return;
- }
-
- columns.splice(columns.indexOf(columnName), 1); // remove at old index
- columns.splice(newIndex, 0, columnName); // insert before new index
+ const modifiedColumns = [...columns];
+ modifiedColumns.splice(modifiedColumns.indexOf(columnName), 1); // remove at old index
+ modifiedColumns.splice(newIndex, 0, columnName); // insert before new index
+ return modifiedColumns;
}
diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_row.ts b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_row.ts
index 8df035d098469..7a090d6b7820c 100644
--- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_row.ts
+++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_row.ts
@@ -33,6 +33,7 @@ import { dispatchRenderComplete } from '../../../../../../../../../plugins/kiban
import cellTemplateHtml from '../components/table_row/cell.html';
import truncateByHeightTemplateHtml from '../components/table_row/truncate_by_height.html';
import { esFilters } from '../../../../../../../../../plugins/data/public';
+import { getServices } from '../../../../kibana_services';
// guesstimate at the minimum number of chars wide cells in the table should be
const MIN_LINE_LENGTH = 20;
@@ -55,7 +56,6 @@ export function createTableRowDirective(
scope: {
columns: '=',
filter: '=',
- filters: '=?',
indexPattern: '=',
row: '=kbnTableRow',
onAddColumn: '=?',
@@ -116,12 +116,18 @@ export function createTableRowDirective(
anchorId: $scope.row._id,
indexPattern: $scope.indexPattern.id,
});
+ const globalFilters: any = getServices().filterManager.getGlobalFilters();
+ const appFilters: any = getServices().filterManager.getAppFilters();
const hash = $httpParamSerializer({
+ _g: rison.encode({
+ filters: globalFilters || [],
+ }),
_a: rison.encode({
columns: $scope.columns,
- filters: ($scope.filters || []).map(esFilters.disableFilter),
+ filters: (appFilters || []).map(esFilters.disableFilter),
}),
});
+
return `${path}?${hash}`;
};
diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/doc_table.html b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/doc_table.html
index 61bb5cbf39cbe..3ce43426caf44 100644
--- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/doc_table.html
+++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/doc_table.html
@@ -43,7 +43,6 @@
sorting="sorting"
index-pattern="indexPattern"
filter="filter"
- filters="filters"
class="kbnDocTable__row"
on-add-column="onAddColumn"
on-remove-column="onRemoveColumn"
@@ -93,7 +92,6 @@
sorting="sorting"
index-pattern="indexPattern"
filter="filter"
- filters="filters"
class="kbnDocTable__row"
ng-class="{'kbnDocTable__row--highlight': row['$$_isAnchor']}"
data-test-subj="docTableRow{{ row['$$_isAnchor'] ? ' docTableAnchorRow' : ''}}"
diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/doc_table.ts b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/doc_table.ts
index 3329ffc7cd102..0ca8286c17081 100644
--- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/doc_table.ts
+++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/doc_table.ts
@@ -17,15 +17,9 @@
* under the License.
*/
-import _ from 'lodash';
import { IUiSettingsClient } from 'kibana/public';
import html from './doc_table.html';
-import './infinite_scroll';
-import './components/table_header';
-import './components/table_row';
import { dispatchRenderComplete } from '../../../../../../../../plugins/kibana_utils/public';
-import './components/pager';
-import './lib/pager';
// @ts-ignore
import { getLimitedSearchResultsMessage } from './doc_table_strings';
@@ -35,7 +29,6 @@ interface LazyScope extends ng.IScope {
export function createDocTableDirective(
config: IUiSettingsClient,
- getAppState: any,
pagerFactory: any,
$filter: any
) {
@@ -51,7 +44,6 @@ export function createDocTableDirective(
isLoading: '=?',
infiniteScroll: '=?',
filter: '=?',
- filters: '=?',
minimumVisibleRows: '=?',
onAddColumn: '=?',
onChangeSortOrder: '=?',
@@ -83,23 +75,6 @@ export function createDocTableDirective(
$scope.limit += 50;
};
- // This exists to fix the problem of an empty initial column list not playing nice with watchCollection.
- $scope.$watch('columns', function(columns: string[]) {
- if (columns.length !== 0) return;
-
- const $state = getAppState();
- $scope.columns.push('_source');
- if ($state) $state.replace();
- });
-
- $scope.$watchCollection('columns', function(columns: string[], oldColumns: string[]) {
- if (oldColumns.length === 1 && oldColumns[0] === '_source' && $scope.columns.length > 1) {
- _.pull($scope.columns, '_source');
- }
-
- if ($scope.columns.length === 0) $scope.columns.push('_source');
- });
-
$scope.$watch('hits', (hits: any) => {
if (!hits) return;
diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/index.ts b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/index.ts
index 1eb1f10114d53..a7e3bdfd57f3b 100644
--- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/index.ts
+++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/index.ts
@@ -17,4 +17,6 @@
* under the License.
*/
-import './doc_table';
+export { createDocTableDirective } from './doc_table';
+export { getSort, getSortArray } from './lib/get_sort';
+export { getSortForSearchSource } from './lib/get_sort_for_search_source';
diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/application.ts b/src/legacy/core_plugins/kibana/public/discover/np_ready/application.ts
index 83f4a5962e3cd..7a4819bb0f2d1 100644
--- a/src/legacy/core_plugins/kibana/public/discover/np_ready/application.ts
+++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/application.ts
@@ -36,8 +36,6 @@ function mountDiscoverApp(moduleName: string, element: HTMLElement) {
// bootstrap angular into detached element and attach it later to
// make angular-within-angular possible
const $injector = angular.bootstrap(mountpoint, [moduleName]);
- // initialize global state handler
- $injector.get('globalState');
element.appendChild(mountpoint);
return $injector;
}
diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/components/field_chooser/discover_index_pattern.test.tsx b/src/legacy/core_plugins/kibana/public/discover/np_ready/components/field_chooser/discover_index_pattern.test.tsx
index b6fd5ee60b8e2..79417c07501a3 100644
--- a/src/legacy/core_plugins/kibana/public/discover/np_ready/components/field_chooser/discover_index_pattern.test.tsx
+++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/components/field_chooser/discover_index_pattern.test.tsx
@@ -25,6 +25,12 @@ import { ChangeIndexPattern } from './change_indexpattern';
import { SavedObject } from 'kibana/server';
import { DiscoverIndexPattern } from './discover_index_pattern';
import { EuiSelectable, EuiSelectableList } from '@elastic/eui';
+import { IIndexPattern } from 'src/plugins/data/public';
+
+const indexPattern = {
+ id: 'test1',
+ title: 'test1 title',
+} as IIndexPattern;
const indexPattern1 = {
id: 'test1',
@@ -42,7 +48,7 @@ const indexPattern2 = {
const defaultProps = {
indexPatternList: [indexPattern1, indexPattern2],
- selectedIndexPattern: indexPattern1,
+ selectedIndexPattern: indexPattern,
setIndexPattern: jest.fn(async () => {}),
};
diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/components/field_chooser/discover_index_pattern.tsx b/src/legacy/core_plugins/kibana/public/discover/np_ready/components/field_chooser/discover_index_pattern.tsx
index cca523ee2c1bd..fd2f96ca83a2f 100644
--- a/src/legacy/core_plugins/kibana/public/discover/np_ready/components/field_chooser/discover_index_pattern.tsx
+++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/components/field_chooser/discover_index_pattern.tsx
@@ -16,9 +16,9 @@
* specific language governing permissions and limitations
* under the License.
*/
-import React, { useState } from 'react';
+import React, { useState, useEffect } from 'react';
import { SavedObject } from 'kibana/server';
-import { IndexPatternAttributes } from 'src/plugins/data/public';
+import { IIndexPattern, IndexPatternAttributes } from 'src/plugins/data/public';
import { I18nProvider } from '@kbn/i18n/react';
import { IndexPatternRef } from './types';
@@ -31,7 +31,7 @@ export interface DiscoverIndexPatternProps {
/**
* currently selected index pattern, due to angular issues it's undefined at first rendering
*/
- selectedIndexPattern: SavedObject;
+ selectedIndexPattern: IIndexPattern;
/**
* triggered when user selects a new index pattern
*/
@@ -50,12 +50,16 @@ export function DiscoverIndexPattern({
id: entity.id,
title: entity.attributes!.title,
}));
- const { id: selectedId, attributes } = selectedIndexPattern || {};
+ const { id: selectedId, title: selectedTitle } = selectedIndexPattern || {};
const [selected, setSelected] = useState({
id: selectedId,
- title: attributes?.title || '',
+ title: selectedTitle || '',
});
+ useEffect(() => {
+ const { id, title } = selectedIndexPattern;
+ setSelected({ id, title });
+ }, [selectedIndexPattern]);
if (!selectedId) {
return null;
}
diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/components/field_chooser/field_chooser.html b/src/legacy/core_plugins/kibana/public/discover/np_ready/components/field_chooser/field_chooser.html
index 1587c2af79752..fd63c26aa2bb3 100644
--- a/src/legacy/core_plugins/kibana/public/discover/np_ready/components/field_chooser/field_chooser.html
+++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/components/field_chooser/field_chooser.html
@@ -1,7 +1,7 @@