From 2052b487ecadf5494e45a8148d199646c3aa3f7d Mon Sep 17 00:00:00 2001 From: Dmitry Tomashevich <39378793+Dmitriynj@users.noreply.github.com> Date: Wed, 16 Mar 2022 12:31:48 +0500 Subject: [PATCH] [Discover] Fix csv export with relative time filter from discover main view (#123206) * [Discover] fix relative time filter for csv export from discover main page * [Discover] fix array assignment * [Discover] fix functional test * [Discover] add test coverage for the issue * [Discover] add debug points for functional test * [Discover] try to get clipboard permissions * [Discover] fix functional test * [Discover] apply suggestion * [Discover] apply suggestion * [Discover] apply naming suggestion Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../main/services/discover_state.ts | 2 +- .../discover/public/utils/get_sharing_data.ts | 19 +++++-- .../functional/apps/discover/reporting.ts | 54 ++++++++++++++++++- 3 files changed, 68 insertions(+), 7 deletions(-) diff --git a/src/plugins/discover/public/application/main/services/discover_state.ts b/src/plugins/discover/public/application/main/services/discover_state.ts index d3ef2aeff393f..0d4c947701379 100644 --- a/src/plugins/discover/public/application/main/services/discover_state.ts +++ b/src/plugins/discover/public/application/main/services/discover_state.ts @@ -315,7 +315,7 @@ export function setState(stateContainer: ReduxLikeStateContainer, newS /** * Helper function to compare 2 different filter states */ -export function isEqualFilters(filtersA: Filter[], filtersB: Filter[]) { +export function isEqualFilters(filtersA?: Filter[] | Filter, filtersB?: Filter[] | Filter) { if (!filtersA && !filtersB) { return true; } else if (!filtersA || !filtersB) { diff --git a/src/plugins/discover/public/utils/get_sharing_data.ts b/src/plugins/discover/public/utils/get_sharing_data.ts index b1c23e1d7bce7..6a74a54071faa 100644 --- a/src/plugins/discover/public/utils/get_sharing_data.ts +++ b/src/plugins/discover/public/utils/get_sharing_data.ts @@ -21,7 +21,7 @@ import { } from '../../common'; import type { SavedSearch, SortOrder } from '../services/saved_searches'; import { getSortForSearchSource } from '../components/doc_table'; -import { AppState } from '../application/main/services/discover_state'; +import { AppState, isEqualFilters } from '../application/main/services/discover_state'; /** * Preparing data to share the current state as link or CSV/Report @@ -34,7 +34,7 @@ export async function getSharingData( const { uiSettings: config, data } = services; const searchSource = currentSearchSource.createCopy(); const index = searchSource.getField('index')!; - const existingFilter = searchSource.getField('filter'); + let existingFilter = searchSource.getField('filter') as Filter[] | Filter | undefined; searchSource.setField( 'sort', @@ -62,11 +62,20 @@ export async function getSharingData( } } + const absoluteTimeFilter = data.query.timefilter.timefilter.createFilter(index); + const relativeTimeFilter = data.query.timefilter.timefilter.createRelativeFilter(index); return { getSearchSource: (absoluteTime?: boolean): SerializedSearchSourceFields => { - const timeFilter = absoluteTime - ? data.query.timefilter.timefilter.createFilter(index) - : data.query.timefilter.timefilter.createRelativeFilter(index); + const timeFilter = absoluteTime ? absoluteTimeFilter : relativeTimeFilter; + + // remove timeFilter from existing filter + if (Array.isArray(existingFilter)) { + existingFilter = existingFilter.filter( + (current) => !isEqualFilters(current, absoluteTimeFilter) + ); + } else if (isEqualFilters(existingFilter, absoluteTimeFilter)) { + existingFilter = undefined; + } if (existingFilter && timeFilter) { searchSource.setField( diff --git a/x-pack/test/functional/apps/discover/reporting.ts b/x-pack/test/functional/apps/discover/reporting.ts index c0e4ebc3f5f4f..55282dd143b7f 100644 --- a/x-pack/test/functional/apps/discover/reporting.ts +++ b/x-pack/test/functional/apps/discover/reporting.ts @@ -6,6 +6,7 @@ */ import expect from '@kbn/expect'; +import { Key } from 'selenium-webdriver'; import moment from 'moment'; import { FtrProviderContext } from '../../ftr_provider_context'; @@ -17,8 +18,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const kibanaServer = getService('kibanaServer'); const browser = getService('browser'); const retry = getService('retry'); - const PageObjects = getPageObjects(['reporting', 'common', 'discover', 'timePicker']); + const PageObjects = getPageObjects(['reporting', 'common', 'discover', 'timePicker', 'share']); const filterBar = getService('filterBar'); + const find = getService('find'); + const testSubjects = getService('testSubjects'); const setFieldsFromSource = async (setValue: boolean) => { await kibanaServer.uiSettings.update({ 'discover:searchFieldsFromSource': setValue }); @@ -76,6 +79,55 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.discover.selectIndexPattern('ecommerce'); }); + it('generates a report with single timefilter', async () => { + await PageObjects.discover.clickNewSearchButton(); + await PageObjects.timePicker.setCommonlyUsedTime('Last_24 hours'); + await PageObjects.discover.saveSearch('single-timefilter-search'); + + // get shared URL value + await PageObjects.share.clickShareTopNavButton(); + const sharedURL = await PageObjects.share.getSharedUrl(); + + // click 'Copy POST URL' + await PageObjects.share.clickShareTopNavButton(); + await PageObjects.reporting.openCsvReportingPanel(); + const advOpt = await find.byXPath(`//button[descendant::*[text()='Advanced options']]`); + await advOpt.click(); + const postUrl = await find.byXPath(`//button[descendant::*[text()='Copy POST URL']]`); + await postUrl.click(); + + // get clipboard value using field search input, since + // 'browser.getClipboardValue()' doesn't work, due to permissions + const textInput = await testSubjects.find('fieldFilterSearchInput'); + await textInput.click(); + await browser.getActions().keyDown(Key.CONTROL).perform(); + await browser.getActions().keyDown('v').perform(); + + const reportURL = decodeURIComponent(await textInput.getAttribute('value')); + + // get number of filters in URLs + const timeFiltersNumberInReportURL = + reportURL.split('query:(range:(order_date:(format:strict_date_optional_time').length - 1; + const timeFiltersNumberInSharedURL = sharedURL.split('time:').length - 1; + + expect(timeFiltersNumberInSharedURL).to.be(1); + expect(sharedURL.includes('time:(from:now-24h%2Fh,to:now))')).to.be(true); + + expect(timeFiltersNumberInReportURL).to.be(1); + expect( + reportURL.includes( + 'query:(range:(order_date:(format:strict_date_optional_time,gte:now-24h/h,lte:now))))' + ) + ).to.be(true); + + // return keyboard state + await browser.getActions().keyUp(Key.CONTROL).perform(); + await browser.getActions().keyUp('v').perform(); + + // return field search input state + await textInput.clearValue(); + }); + it('generates a report from a new search with data: default', async () => { await PageObjects.discover.clickNewSearchButton(); await PageObjects.reporting.setTimepickerInEcommerceDataRange();