mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
* fixing embedded mode in visualize (#21468) # Conflicts: # test/functional/config.js # test/functional/services/index.js * fixing tests
This commit is contained in:
parent
5f66ba8463
commit
2d4a54efa5
9 changed files with 163 additions and 31 deletions
|
@ -200,16 +200,22 @@ export class DashboardStateManager {
|
|||
store.dispatch(updateDescription(this.getDescription()));
|
||||
}
|
||||
|
||||
if (!_.isEqual(
|
||||
FilterUtils.cleanFiltersForComparison(this.appState.filters),
|
||||
FilterUtils.cleanFiltersForComparison(getFilters(state))
|
||||
)) {
|
||||
store.dispatch(updateFilters(this.appState.filters));
|
||||
}
|
||||
|
||||
if (getQuery(state) !== this.getQuery()) {
|
||||
store.dispatch(updateQuery(this.getQuery()));
|
||||
}
|
||||
|
||||
this._pushFiltersToStore();
|
||||
}
|
||||
|
||||
_pushFiltersToStore() {
|
||||
const state = store.getState();
|
||||
const dashboardFilters = this.getDashboardFilterBars();
|
||||
if (!_.isEqual(
|
||||
FilterUtils.cleanFiltersForComparison(dashboardFilters),
|
||||
FilterUtils.cleanFiltersForComparison(getFilters(state))
|
||||
)) {
|
||||
store.dispatch(updateFilters(dashboardFilters));
|
||||
}
|
||||
}
|
||||
|
||||
_handleStoreChanges() {
|
||||
|
@ -582,6 +588,8 @@ export class DashboardStateManager {
|
|||
this.savedDashboard.searchSource.setField('query', query);
|
||||
this.savedDashboard.searchSource.setField('filter', filters);
|
||||
this.saveState();
|
||||
// pinned filters go on global state, therefore are not propagated to store via app state and have to be pushed manually.
|
||||
this._pushFiltersToStore();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
</a>
|
||||
|
||||
<a
|
||||
data-test-subj="unlinkSavedSearch"
|
||||
href=""
|
||||
ng-dblclick="unlink()"
|
||||
tooltip="Double click to unlink from Saved Search"
|
||||
|
|
|
@ -125,6 +125,19 @@ function VisEditor(
|
|||
// vis is instance of src/ui/public/vis/vis.js.
|
||||
// SearchSource is a promise-based stream of search results that can inherit from other search sources.
|
||||
const { vis, searchSource } = savedVis;
|
||||
|
||||
// adds top level search source to the stack to which global filters are applied
|
||||
const getTopLevelSearchSource = (searchSource) => {
|
||||
if (searchSource.getParent()) return getTopLevelSearchSource(searchSource.getParent());
|
||||
return searchSource;
|
||||
};
|
||||
|
||||
const topLevelSearchSource = getTopLevelSearchSource(searchSource);
|
||||
const globalFiltersSearchSource = searchSource.create();
|
||||
globalFiltersSearchSource.setField('index', searchSource.getField('index'));
|
||||
topLevelSearchSource.setParent(globalFiltersSearchSource);
|
||||
|
||||
|
||||
$scope.vis = vis;
|
||||
|
||||
$scope.topNavMenu = [{
|
||||
|
@ -281,8 +294,10 @@ function VisEditor(
|
|||
// update the searchSource when query updates
|
||||
$scope.fetch = function () {
|
||||
$state.save();
|
||||
const globalFilters = queryFilter.getGlobalFilters();
|
||||
savedVis.searchSource.setField('query', $state.query);
|
||||
savedVis.searchSource.setField('filter', $state.filters);
|
||||
globalFiltersSearchSource.setField('filter', globalFilters);
|
||||
$scope.vis.forceReload();
|
||||
};
|
||||
|
||||
|
@ -361,27 +376,20 @@ function VisEditor(
|
|||
$scope.unlink = function () {
|
||||
if (!$state.linked) return;
|
||||
|
||||
toastNotifications.addSuccess(`Unlinked from saved search '${savedVis.savedSearch.title}'`);
|
||||
|
||||
$state.linked = false;
|
||||
const searchSourceParent = searchSource.getParent(true);
|
||||
const searchSourceGrandparent = searchSourceParent.getParent(true);
|
||||
const searchSourceParent = searchSource.getParent();
|
||||
const searchSourceGrandparent = searchSourceParent.getParent();
|
||||
|
||||
delete savedVis.savedSearchId;
|
||||
searchSourceParent.setField('filter', _.union(searchSource.getOwnField('filter'), searchSourceParent.getOwnField('filter')));
|
||||
|
||||
// copy over all state except "aggs", "query" and "filter"
|
||||
_(searchSourceParent.toJSON())
|
||||
.omit(['aggs', 'filter', 'query'])
|
||||
.forOwn(function (val, key) {
|
||||
searchSource.setField(key, val);
|
||||
})
|
||||
.commit();
|
||||
|
||||
$state.query = searchSource.getField('query');
|
||||
$state.filters = searchSource.getField('filter');
|
||||
$state.query = searchSourceParent.getField('query');
|
||||
$state.filters = searchSourceParent.getField('filter');
|
||||
searchSource.setField('index', searchSourceParent.getField('index'));
|
||||
searchSource.setParent(searchSourceGrandparent);
|
||||
|
||||
toastNotifications.addSuccess(`Unlinked from saved search '${savedVis.savedSearch.title}'`);
|
||||
|
||||
$scope.fetch();
|
||||
};
|
||||
|
||||
|
|
|
@ -104,6 +104,63 @@ export default function ({ getService, getPageObjects }) {
|
|||
});
|
||||
});
|
||||
|
||||
describe.skip('using a pinned filter that excludes all data', async () => {
|
||||
before(async () => {
|
||||
await filterBar.toggleFilterPinned('bytes');
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await PageObjects.dashboard.waitForRenderComplete();
|
||||
});
|
||||
|
||||
it('filters on pie charts', async () => {
|
||||
await dashboardExpect.pieSliceCount(0);
|
||||
});
|
||||
|
||||
it('area, bar and heatmap charts filtered', async () => {
|
||||
await dashboardExpect.seriesElementCount(0);
|
||||
});
|
||||
|
||||
it('data tables are filtered', async () => {
|
||||
await dashboardExpect.dataTableRowCount(0);
|
||||
});
|
||||
|
||||
it('goal and guages are filtered', async () => {
|
||||
await dashboardExpect.goalAndGuageLabelsExist(['0', '0%']);
|
||||
});
|
||||
|
||||
it('tsvb time series shows no data message', async () => {
|
||||
expect(await testSubjects.exists('noTSVBDataMessage')).to.be(true);
|
||||
await dashboardExpect.tsvbTimeSeriesLegendCount(0);
|
||||
});
|
||||
|
||||
it('metric value shows no data', async () => {
|
||||
await dashboardExpect.metricValuesExist(['-']);
|
||||
});
|
||||
|
||||
it('tag cloud values are filtered', async () => {
|
||||
await dashboardExpect.emptyTagCloudFound();
|
||||
});
|
||||
|
||||
it('tsvb metric is filtered', async () => {
|
||||
await dashboardExpect.tsvbMetricValuesExist(['0 custom template']);
|
||||
});
|
||||
|
||||
it('tsvb top n is filtered', async () => {
|
||||
await dashboardExpect.tsvbTopNValuesExist(['0', '0']);
|
||||
});
|
||||
|
||||
it('saved search is filtered', async () => {
|
||||
await dashboardExpect.savedSearchRowCount(0);
|
||||
});
|
||||
|
||||
it('timelion is filtered', async () => {
|
||||
await dashboardExpect.timelionLegendCount(0);
|
||||
});
|
||||
|
||||
it('vega is filtered', async () => {
|
||||
await dashboardExpect.vegaTextsDoNotExist(['5,000']);
|
||||
});
|
||||
});
|
||||
|
||||
// Skipped because it depends on filter applied by disabled test
|
||||
describe.skip('disabling a filter unfilters the data on', async () => {
|
||||
before(async () => {
|
||||
|
|
|
@ -161,7 +161,15 @@ export default function ({ getService, getPageObjects }) {
|
|||
it('should correctly filter for applied time filter on the main timefield', async () => {
|
||||
await filterBar.addFilter('@timestamp', 'is between', ['2015-09-19', '2015-09-21']);
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await PageObjects.common.sleep(1000);
|
||||
const data = await PageObjects.visualize.getTableVisData();
|
||||
expect(data.trim().split('\n')).to.be.eql([
|
||||
'2015-09-20', '4,757',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should correctly filter for pinned filters', async () => {
|
||||
await filterBar.toggleFilterPinned('@timestamp');
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
const data = await PageObjects.visualize.getTableVisData();
|
||||
expect(data.trim().split('\n')).to.be.eql([
|
||||
'2015-09-20', '4,757',
|
||||
|
|
|
@ -19,11 +19,11 @@
|
|||
|
||||
import expect from 'expect.js';
|
||||
|
||||
export default function ({ getPageObjects }) {
|
||||
export default function ({ getService, getPageObjects }) {
|
||||
const filterBar = getService('filterBar');
|
||||
const PageObjects = getPageObjects(['common', 'discover', 'visualize', 'header']);
|
||||
|
||||
// Blocked by: https://github.com/elastic/kibana/issues/19750
|
||||
describe.skip('visualize app', function describeIndexTests() {
|
||||
describe('visualize app', function describeIndexTests() {
|
||||
const fromTime = '2015-09-19 06:31:44.000';
|
||||
const toTime = '2015-09-23 18:31:44.000';
|
||||
|
||||
|
@ -32,8 +32,12 @@ export default function ({ getPageObjects }) {
|
|||
const savedSearchName = 'vis_saved_search';
|
||||
|
||||
before(async () => {
|
||||
await PageObjects.common.navigateToUrl('discover', '');
|
||||
await PageObjects.common.navigateToApp('discover');
|
||||
await filterBar.addFilter('extension.raw', 'is', 'jpg');
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await PageObjects.discover.saveSearch(savedSearchName);
|
||||
// TODO: Remove this once https://github.com/elastic/kibana/issues/19750 is properly resolved
|
||||
await PageObjects.common.sleep(500);
|
||||
});
|
||||
|
||||
it('should create a visualization from a saved search', async () => {
|
||||
|
@ -43,19 +47,44 @@ export default function ({ getPageObjects }) {
|
|||
await PageObjects.header.setAbsoluteRange(fromTime, toTime);
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
const data = await PageObjects.visualize.getTableVisData();
|
||||
expect(data.trim()).to.be('14,004');
|
||||
expect(data.trim()).to.be('9,109');
|
||||
});
|
||||
|
||||
it('should respect the time filter when linked to a saved search', async () => {
|
||||
await PageObjects.header.setAbsoluteRange('2015-09-19 06:31:44.000', '2015-09-21 10:00:00.000');
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
const data = await PageObjects.visualize.getTableVisData();
|
||||
expect(data.trim()).to.be('6,086');
|
||||
expect(data.trim()).to.be('3,950');
|
||||
});
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await PageObjects.header.setAbsoluteRange(fromTime, toTime);
|
||||
it('should allow adding filters while having a linked saved search', async () => {
|
||||
await filterBar.addFilter('bytes', 'is between', ['100', '3000']);
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
const data = await PageObjects.visualize.getTableVisData();
|
||||
expect(data.trim()).to.be('707');
|
||||
});
|
||||
|
||||
it('should allow unlinking from a linked search', async () => {
|
||||
await PageObjects.visualize.clickUnlinkSavedSearch();
|
||||
const data = await PageObjects.visualize.getTableVisData();
|
||||
expect(data.trim()).to.be('707');
|
||||
// The filter on the saved search should now be in the editor
|
||||
expect(await filterBar.hasFilter('extension.raw', 'jpg')).to.be(true);
|
||||
|
||||
// Disabling this filter should now result in different values, since
|
||||
// the visualization should not be linked anymore with the saved search.
|
||||
await filterBar.toggleFilterEnabled('extension.raw');
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
const unfilteredData = await PageObjects.visualize.getTableVisData();
|
||||
expect(unfilteredData.trim()).to.be('1,293');
|
||||
});
|
||||
|
||||
it('should not break when saving after unlinking', async () => {
|
||||
await PageObjects.visualize.saveVisualization('Unlinked before saved');
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
const data = await PageObjects.visualize.getTableVisData();
|
||||
expect(data.trim()).to.be('1,293');
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -449,6 +449,11 @@ export function VisualizePageProvider({ getService, getPageObjects }) {
|
|||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
}
|
||||
|
||||
async clickUnlinkSavedSearch() {
|
||||
await testSubjects.doubleClick('unlinkSavedSearch');
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
}
|
||||
|
||||
async setValue(newValue) {
|
||||
await find.clickByCssSelector('button[ng-click="numberListCntr.add()"]', defaultFindTimeout * 2);
|
||||
const input = await find.byCssSelector('input[ng-model="numberListCntr.getList()[$index]"]');
|
||||
|
|
|
@ -50,6 +50,12 @@ export function FilterBarProvider({ getService }) {
|
|||
await testSubjects.click(`filter & filter-key-${key} disableFilter-${key}`);
|
||||
}
|
||||
|
||||
async toggleFilterPinned(key) {
|
||||
const filterElement = await testSubjects.find(`filter & filter-key-${key}`);
|
||||
await remote.moveMouseTo(filterElement);
|
||||
await testSubjects.click(`filter & filter-key-${key} pinFilter-${key}`);
|
||||
}
|
||||
|
||||
async addFilter(field, operator, values) {
|
||||
if (!Array.isArray(values)) {
|
||||
values = [values];
|
||||
|
|
|
@ -54,6 +54,16 @@ export function TestSubjectsProvider({ getService }) {
|
|||
});
|
||||
}
|
||||
|
||||
async doubleClick(selector, timeout = defaultFindTimeout) {
|
||||
log.debug(`TestSubjects.doubleClick(${selector})`);
|
||||
return await retry.try(async () => {
|
||||
const element = await this.find(selector, timeout);
|
||||
await remote.moveMouseTo(element);
|
||||
await remote.doubleClick();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
async descendantExists(selector, parentElement) {
|
||||
return await find.descendantExistsByCssSelector(testSubjSelector(selector), parentElement);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue