Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Reporting/Discover/Search Sessions] Only use relative time filter wh…
Browse files Browse the repository at this point in the history
…en generating share data (elastic#112588)

* only use relative time filter when generating share data

* Added comment on absolute time filter.

Co-authored-by: Tim Sullivan <[email protected]>

* improve discover search session relative time range test

* update discover tests and types for passing in data plugin to getSharingData function

* updated reporting to pass in data plugin to getSharingData, also updates jest tests

Co-authored-by: Kibana Machine <[email protected]>
Co-authored-by: Tim Sullivan <[email protected]>
Co-authored-by: Anton Dosov <[email protected]>
4 people committed Sep 21, 2021

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
1 parent 7d99d74 commit 8eff2bb
Showing 9 changed files with 104 additions and 68 deletions.
Original file line number Diff line number Diff line change
@@ -112,7 +112,7 @@ export const getTopNavLinks = ({
const sharingData = await getSharingData(
searchSource,
state.appStateContainer.getState(),
services.uiSettings
services
);

services.share.toggleShareContextMenu({
Original file line number Diff line number Diff line change
@@ -7,32 +7,37 @@
*/

import { Capabilities, IUiSettingsClient } from 'kibana/public';
import { IndexPattern } from 'src/plugins/data/public';
import type { IndexPattern } from 'src/plugins/data/public';
import type { DiscoverServices } from '../../../../build_services';
import { dataPluginMock } from '../../../../../../data/public/mocks';
import { createSearchSourceMock } from '../../../../../../data/common/search/search_source/mocks';
import { DOC_HIDE_TIME_COLUMN_SETTING, SORT_DEFAULT_ORDER_SETTING } from '../../../../../common';
import { indexPatternMock } from '../../../../__mocks__/index_pattern';
import { getSharingData, showPublicUrlSwitch } from './get_sharing_data';

describe('getSharingData', () => {
let mockConfig: IUiSettingsClient;
let services: DiscoverServices;

beforeEach(() => {
mockConfig = ({
get: (key: string) => {
if (key === SORT_DEFAULT_ORDER_SETTING) {
return 'desc';
}
if (key === DOC_HIDE_TIME_COLUMN_SETTING) {
services = {
data: dataPluginMock.createStartContract(),
uiSettings: {
get: (key: string) => {
if (key === SORT_DEFAULT_ORDER_SETTING) {
return 'desc';
}
if (key === DOC_HIDE_TIME_COLUMN_SETTING) {
return false;
}
return false;
}
return false;
},
},
} as unknown) as IUiSettingsClient;
} as DiscoverServices;
});

test('returns valid data for sharing', async () => {
const searchSourceMock = createSearchSourceMock({ index: indexPatternMock });
const result = await getSharingData(searchSourceMock, { columns: [] }, mockConfig);
const result = await getSharingData(searchSourceMock, { columns: [] }, services);
expect(result).toMatchInlineSnapshot(`
Object {
"columns": Array [],
@@ -53,7 +58,7 @@ describe('getSharingData', () => {
const result = await getSharingData(
searchSourceMock,
{ columns: ['column_a', 'column_b'] },
mockConfig
services
);
expect(result).toMatchInlineSnapshot(`
Object {
@@ -90,7 +95,7 @@ describe('getSharingData', () => {
'cool-field-6',
],
},
mockConfig
services
);
expect(result).toMatchInlineSnapshot(`
Object {
@@ -116,7 +121,7 @@ describe('getSharingData', () => {
});

test('fields conditionally do not have prepended timeField', async () => {
mockConfig = ({
services.uiSettings = ({
get: (key: string) => {
if (key === DOC_HIDE_TIME_COLUMN_SETTING) {
return true;
@@ -141,7 +146,7 @@ describe('getSharingData', () => {
'cool-field-6',
],
},
mockConfig
services
);
expect(result).toMatchInlineSnapshot(`
Object {
Original file line number Diff line number Diff line change
@@ -6,8 +6,10 @@
* Side Public License, v 1.
*/

import type { Capabilities, IUiSettingsClient } from 'kibana/public';
import { ISearchSource } from '../../../../../../data/common';
import type { Capabilities } from 'kibana/public';
import type { IUiSettingsClient } from 'src/core/public';
import type { DataPublicPluginStart } from 'src/plugins/data/public';
import type { ISearchSource } from 'src/plugins/data/common';
import { DOC_HIDE_TIME_COLUMN_SETTING, SORT_DEFAULT_ORDER_SETTING } from '../../../../../common';
import type { SavedSearch, SortOrder } from '../../../../saved_searches/types';
import { getSortForSearchSource } from '../components/doc_table';
@@ -19,15 +21,18 @@ import { AppState } from '../services/discover_state';
export async function getSharingData(
currentSearchSource: ISearchSource,
state: AppState | SavedSearch,
config: IUiSettingsClient
services: { uiSettings: IUiSettingsClient; data: DataPublicPluginStart }
) {
const { uiSettings: config, data } = services;
const searchSource = currentSearchSource.createCopy();
const index = searchSource.getField('index')!;

searchSource.setField(
'sort',
getSortForSearchSource(state.sort as SortOrder[], index, config.get(SORT_DEFAULT_ORDER_SETTING))
);
// When sharing externally we preserve relative time values
searchSource.setField('filter', data.query.timefilter.timefilter.createRelativeFilter(index));
searchSource.removeField('highlight');
searchSource.removeField('highlightAll');
searchSource.removeField('aggs');
Original file line number Diff line number Diff line change
@@ -54,10 +54,8 @@ export function updateSearchSource(

// this is not the default index pattern, it determines that it's not of type rollup
if (indexPatternsUtils.isDefault(indexPattern)) {
searchSource.setField(
'filter',
data.query.timefilter.timefilter.createRelativeFilter(indexPattern)
);
// Set the date range filter fields from timeFilter using the absolute format. Search sessions requires that it be converted from a relative range
searchSource.setField('filter', data.query.timefilter.timefilter.createFilter(indexPattern));
}

if (useNewFieldsApi) {
Original file line number Diff line number Diff line change
@@ -8,9 +8,14 @@
import * as Rx from 'rxjs';
import { first } from 'rxjs/operators';
import { CoreStart } from 'src/core/public';
import type { SearchSource } from 'src/plugins/data/common';
import type { SavedSearch } from 'src/plugins/discover/public';
import { coreMock } from '../../../../../src/core/public/mocks';
import { LicensingPluginSetup } from '../../../licensing/public';
import { dataPluginMock } from '../../../../../src/plugins/data/public/mocks';
import type { ILicense, LicensingPluginSetup } from '../../../licensing/public';
import { ReportingAPIClient } from '../lib/reporting_api_client';
import type { ReportingPublicPluginStartDendencies } from '../plugin';
import type { ActionContext } from './get_csv_panel_action';
import { ReportingCsvPanelAction } from './get_csv_panel_action';

type LicenseResults = 'valid' | 'invalid' | 'unavailable' | 'expired';
@@ -19,11 +24,11 @@ const core = coreMock.createSetup();
let apiClient: ReportingAPIClient;

describe('GetCsvReportPanelAction', () => {
let context: any;
let mockLicense$: any;
let mockSearchSource: any;
let mockStartServicesPayload: [CoreStart, object, unknown];
let mockStartServices$: Rx.Subject<typeof mockStartServicesPayload>;
let context: ActionContext;
let mockLicense$: (state?: LicenseResults) => Rx.Observable<ILicense>;
let mockSearchSource: SearchSource;
let mockStartServicesPayload: [CoreStart, ReportingPublicPluginStartDendencies, unknown];
let mockStartServices$: Rx.Observable<typeof mockStartServicesPayload>;

beforeAll(() => {
if (typeof window.URL.revokeObjectURL === 'undefined') {
@@ -45,24 +50,27 @@ describe('GetCsvReportPanelAction', () => {
}) as unknown) as LicensingPluginSetup['license$'];
};

mockStartServices$ = new Rx.Subject<[CoreStart, object, unknown]>();
mockStartServicesPayload = [
({
...core,
application: { capabilities: { dashboard: { downloadCsv: true } } },
} as unknown) as CoreStart,
{},
{
data: dataPluginMock.createStartContract(),
} as ReportingPublicPluginStartDendencies,
null,
];
mockStartServices$ = Rx.from(Promise.resolve(mockStartServicesPayload));

mockSearchSource = {
mockSearchSource = ({
createCopy: () => mockSearchSource,
removeField: jest.fn(),
setField: jest.fn(),
getField: jest.fn(),
getSerializedFields: jest.fn().mockImplementation(() => ({})),
};
} as unknown) as SearchSource;

context = {
context = ({
embeddable: {
type: 'search',
getSavedSearch: () => {
@@ -78,7 +86,7 @@ describe('GetCsvReportPanelAction', () => {
},
}),
},
} as any;
} as unknown) as ActionContext;
});

it('translates empty embeddable context into job params', async () => {
@@ -90,7 +98,7 @@ describe('GetCsvReportPanelAction', () => {
usesUiCapabilities: true,
});

mockStartServices$.next(mockStartServicesPayload);
await mockStartServices$.pipe(first()).toPromise();

await panel.execute(context);

@@ -105,18 +113,18 @@ describe('GetCsvReportPanelAction', () => {
});

it('translates embeddable context into job params', async () => {
mockSearchSource = {
mockSearchSource = ({
createCopy: () => mockSearchSource,
removeField: jest.fn(),
setField: jest.fn(),
getField: jest.fn(),
getSerializedFields: jest.fn().mockImplementation(() => ({ testData: 'testDataValue' })),
};
} as unknown) as SearchSource;
context.embeddable.getSavedSearch = () => {
return {
return ({
searchSource: mockSearchSource,
columns: ['column_a', 'column_b'],
};
} as unknown) as SavedSearch;
};

const panel = new ReportingCsvPanelAction({
@@ -127,7 +135,7 @@ describe('GetCsvReportPanelAction', () => {
usesUiCapabilities: true,
});

mockStartServices$.next(mockStartServicesPayload);
await mockStartServices$.pipe(first()).toPromise();

await panel.execute(context);

@@ -150,7 +158,7 @@ describe('GetCsvReportPanelAction', () => {
usesUiCapabilities: true,
});

mockStartServices$.next(mockStartServicesPayload);
await mockStartServices$.pipe(first()).toPromise();

await panel.execute(context);

@@ -166,7 +174,7 @@ describe('GetCsvReportPanelAction', () => {
usesUiCapabilities: true,
});

mockStartServices$.next(mockStartServicesPayload);
await mockStartServices$.pipe(first()).toPromise();

await panel.execute(context);

@@ -184,7 +192,7 @@ describe('GetCsvReportPanelAction', () => {
usesUiCapabilities: true,
});

mockStartServices$.next(mockStartServicesPayload);
await mockStartServices$.pipe(first()).toPromise();

await panel.execute(context);

@@ -201,14 +209,13 @@ describe('GetCsvReportPanelAction', () => {
usesUiCapabilities: true,
});

mockStartServices$.next(mockStartServicesPayload);

await mockStartServices$.pipe(first()).toPromise();
await licenseMock$.pipe(first()).toPromise();

expect(await plugin.isCompatible(context)).toEqual(false);
});

it('sets a display and icon type', () => {
it('sets a display and icon type', async () => {
const panel = new ReportingCsvPanelAction({
core,
apiClient,
@@ -217,33 +224,36 @@ describe('GetCsvReportPanelAction', () => {
usesUiCapabilities: true,
});

mockStartServices$.next(mockStartServicesPayload);
await mockStartServices$.pipe(first()).toPromise();

expect(panel.getIconType()).toMatchInlineSnapshot(`"document"`);
expect(panel.getDisplayName()).toMatchInlineSnapshot(`"Download CSV"`);
});

describe('Application UI Capabilities', () => {
it(`doesn't allow downloads when UI capability is not enabled`, async () => {
mockStartServicesPayload = [
({ application: { capabilities: {} } } as unknown) as CoreStart,
{
data: dataPluginMock.createStartContract(),
} as ReportingPublicPluginStartDendencies,
null,
];
const startServices$ = Rx.from(Promise.resolve(mockStartServicesPayload));
const plugin = new ReportingCsvPanelAction({
core,
apiClient,
license$: mockLicense$(),
startServices$: mockStartServices$,
startServices$,
usesUiCapabilities: true,
});

mockStartServices$.next([
({ application: { capabilities: {} } } as unknown) as CoreStart,
{},
null,
]);
await startServices$.pipe(first()).toPromise();

expect(await plugin.isCompatible(context)).toEqual(false);
});

it(`allows downloads when license is valid and UI capability is enabled`, async () => {
mockStartServices$ = new Rx.Subject();
const plugin = new ReportingCsvPanelAction({
core,
apiClient,
@@ -252,7 +262,7 @@ describe('GetCsvReportPanelAction', () => {
usesUiCapabilities: true,
});

mockStartServices$.next(mockStartServicesPayload);
await mockStartServices$.pipe(first()).toPromise();

expect(await plugin.isCompatible(context)).toEqual(true);
});
Loading

0 comments on commit 8eff2bb

Please sign in to comment.