Skip to content

Commit

Permalink
fix 'Download CSV' returns no data when panel has custom time range o…
Browse files Browse the repository at this point in the history
…utside timerange of global time picker (elastic#163887)

Closes elastic#163614

PR resolves issue by only adding global time filter to CSV export body
when saved search embeddable does not have time range.

---------

Co-authored-by: kibanamachine <[email protected]>
(cherry picked from commit 53e803e)
  • Loading branch information
nreese committed Aug 17, 2023
1 parent 0cbca7a commit 42da150
Show file tree
Hide file tree
Showing 10 changed files with 249 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -770,4 +770,8 @@ export class SavedSearchEmbeddable
this.subscription?.unsubscribe();
this.abortController?.abort();
}

public hasTimeRange() {
return this.getTimeRange() !== undefined;
}
}
1 change: 1 addition & 0 deletions src/plugins/discover/public/embeddable/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export interface SearchOutput extends EmbeddableOutput {

export interface ISearchEmbeddable extends IEmbeddable<SearchInput, SearchOutput> {
getSavedSearch(): SavedSearch;
hasTimeRange(): boolean;
}

export interface SearchEmbeddable extends Embeddable<SearchInput, SearchOutput> {
Expand Down
6 changes: 3 additions & 3 deletions src/plugins/discover/public/utils/get_sharing_data.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ describe('getSharingData', () => {
index.timeFieldName = 'cool-timefield';
const searchSourceMock = createSearchSourceMock({ index });
const { getSearchSource } = await getSharingData(searchSourceMock, {}, services);
expect(getSearchSource()).toMatchInlineSnapshot(`
expect(getSearchSource({})).toMatchInlineSnapshot(`
Object {
"fields": Array [
Object {
Expand Down Expand Up @@ -121,7 +121,7 @@ describe('getSharingData', () => {
},
services
);
expect(getSearchSource()).toMatchInlineSnapshot(`
expect(getSearchSource({})).toMatchInlineSnapshot(`
Object {
"index": "the-data-view-id",
"sort": Array [
Expand Down Expand Up @@ -151,7 +151,7 @@ describe('getSharingData', () => {
},
services
);
expect(getSearchSource().fields).toStrictEqual([
expect(getSearchSource({}).fields).toStrictEqual([
{ field: 'cool-timefield', include_unmapped: 'true' },
{ field: 'cool-field-1', include_unmapped: 'true' },
{ field: 'cool-field-2', include_unmapped: 'true' },
Expand Down
43 changes: 25 additions & 18 deletions src/plugins/discover/public/utils/get_sharing_data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,28 +69,35 @@ 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 => {
getSearchSource: ({
addGlobalTimeFilter,
absoluteTime,
}: {
addGlobalTimeFilter?: boolean;
absoluteTime?: boolean;
}): SerializedSearchSourceFields => {
const timeFilter = absoluteTime ? absoluteTimeFilter : relativeTimeFilter;
if (addGlobalTimeFilter && timeFilter) {
// remove timeFilter from existing filter
if (Array.isArray(existingFilter)) {
existingFilter = existingFilter.filter(
(current) => !isEqualFilters(current, absoluteTimeFilter)
);
} else if (isEqualFilters(existingFilter, absoluteTimeFilter)) {
existingFilter = undefined;
}

// 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) {
existingFilter = Array.isArray(existingFilter)
? [timeFilter, ...existingFilter]
: ([timeFilter, existingFilter] as Filter[]);
} else {
existingFilter = timeFilter;
}
}

if (existingFilter && timeFilter) {
searchSource.setField(
'filter',
Array.isArray(existingFilter)
? [timeFilter, ...existingFilter]
: ([timeFilter, existingFilter] as Filter[])
);
} else {
const filter = timeFilter || existingFilter;
searchSource.setField('filter', filter);
if (existingFilter) {
searchSource.setField('filter', existingFilter);
}

/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ describe('GetCsvReportPanelAction', () => {
from: 'now-7d',
},
}),
hasTimeRange: () => true,
},
} as unknown as ActionContext;
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export class ReportingCsvPanelAction implements ActionDefinition<ActionContext>
});
}

public async getSearchSource(savedSearch: SavedSearch, _embeddable: ISearchEmbeddable) {
public async getSharingData(savedSearch: SavedSearch) {
const [{ uiSettings }, { data }] = await Rx.firstValueFrom(this.startServices$);
const { getSharingData } = await loadSharingDataHelpers();
return await getSharingData(savedSearch.searchSource, savedSearch, { uiSettings, data });
Expand Down Expand Up @@ -126,10 +126,13 @@ export class ReportingCsvPanelAction implements ActionDefinition<ActionContext>
}

const savedSearch = embeddable.getSavedSearch();
const { columns, getSearchSource } = await this.getSearchSource(savedSearch, embeddable);
const { columns, getSearchSource } = await this.getSharingData(savedSearch);

const immediateJobParams = this.apiClient.getDecoratedJobParams({
searchSource: getSearchSource(true),
searchSource: getSearchSource({
addGlobalTimeFilter: !embeddable.hasTimeRange(),
absoluteTime: true,
}),
columns,
title: savedSearch.title || '',
objectType: 'downloadCsv', // FIXME: added for typescript, but immediate download job does not need objectType
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,13 @@ export const reportingCsvShareProvider = ({
return [];
}

const getSearchSource = sharingData.getSearchSource as (
absoluteTime?: boolean
) => SearchSourceFields;
const getSearchSource = sharingData.getSearchSource as ({
addGlobalTimeFilter,
absoluteTime,
}: {
addGlobalTimeFilter?: boolean;
absoluteTime?: boolean;
}) => SearchSourceFields;

const jobParams = {
title: sharingData.title as string,
Expand All @@ -39,10 +43,12 @@ export const reportingCsvShareProvider = ({
};

const getJobParams = (forShareUrl?: boolean) => {
const absoluteTime = !forShareUrl;
return {
...jobParams,
searchSource: getSearchSource(absoluteTime),
searchSource: getSearchSource({
addGlobalTimeFilter: true,
absoluteTime: !forShareUrl,
}),
};
};

Expand Down
Loading

0 comments on commit 42da150

Please sign in to comment.