mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[Discover] Make share links and search session info shorter for ad-hoc data views (#161180)
- Closes https://github.com/elastic/kibana/issues/160993 ## Summary This PR introduces `dataView.toMinimalSpec()` which is used now in 3 cases: - when constructing an alert link - when constructing a share URL for ad-hoc data views - when constructing search session info for ad-hoc data views --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
618c7fa32b
commit
8b42e0f79b
9 changed files with 189 additions and 50 deletions
|
@ -114,6 +114,7 @@ export const buildDataViewMock = ({
|
|||
isTimeNanosBased: () => false,
|
||||
isPersisted: () => true,
|
||||
toSpec: () => ({}),
|
||||
toMinimalSpec: () => ({}),
|
||||
getTimeField: () => {
|
||||
return dataViewFields.find((field) => field.name === timeFieldName);
|
||||
},
|
||||
|
|
|
@ -26,6 +26,29 @@ Object {
|
|||
}
|
||||
`;
|
||||
|
||||
exports[`IndexPattern toMinimalSpec can exclude fields 1`] = `
|
||||
Object {
|
||||
"allowNoIndex": false,
|
||||
"fieldAttrs": undefined,
|
||||
"fieldFormats": Object {},
|
||||
"id": "test-pattern",
|
||||
"name": "Name",
|
||||
"runtimeFieldMap": Object {
|
||||
"runtime_field": Object {
|
||||
"script": Object {
|
||||
"source": "emit('hello world')",
|
||||
},
|
||||
"type": "keyword",
|
||||
},
|
||||
},
|
||||
"sourceFilters": Array [],
|
||||
"timeFieldName": "time",
|
||||
"title": "title",
|
||||
"type": "index-pattern",
|
||||
"version": "2",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`IndexPattern toSpec can optionally exclude fields 1`] = `
|
||||
Object {
|
||||
"allowNoIndex": false,
|
||||
|
|
|
@ -478,4 +478,111 @@ describe('IndexPattern', () => {
|
|||
expect(dataView1.sourceFilters).not.toBe(dataView2.sourceFilters);
|
||||
});
|
||||
});
|
||||
|
||||
describe('toMinimalSpec', () => {
|
||||
test('can exclude fields', () => {
|
||||
expect(indexPattern.toMinimalSpec()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('can omit counts', () => {
|
||||
const fieldsMap = {
|
||||
test1: {
|
||||
name: 'test1',
|
||||
type: 'keyword',
|
||||
aggregatable: true,
|
||||
searchable: true,
|
||||
readFromDocValues: false,
|
||||
},
|
||||
test2: {
|
||||
name: 'test2',
|
||||
type: 'keyword',
|
||||
aggregatable: true,
|
||||
searchable: true,
|
||||
readFromDocValues: false,
|
||||
},
|
||||
test3: {
|
||||
name: 'test3',
|
||||
type: 'keyword',
|
||||
aggregatable: true,
|
||||
searchable: true,
|
||||
readFromDocValues: false,
|
||||
},
|
||||
};
|
||||
expect(
|
||||
create('test', {
|
||||
id: 'test',
|
||||
title: 'test*',
|
||||
fields: fieldsMap,
|
||||
fieldAttrs: undefined,
|
||||
}).toMinimalSpec().fieldAttrs
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
create('test', {
|
||||
id: 'test',
|
||||
title: 'test*',
|
||||
fields: fieldsMap,
|
||||
fieldAttrs: {
|
||||
test1: {
|
||||
count: 11,
|
||||
},
|
||||
test2: {
|
||||
count: 12,
|
||||
},
|
||||
},
|
||||
}).toMinimalSpec().fieldAttrs
|
||||
).toBeUndefined();
|
||||
|
||||
expect(
|
||||
create('test', {
|
||||
id: 'test',
|
||||
title: 'test*',
|
||||
fields: fieldsMap,
|
||||
fieldAttrs: {
|
||||
test1: {
|
||||
count: 11,
|
||||
customLabel: 'test11',
|
||||
},
|
||||
test2: {
|
||||
count: 12,
|
||||
},
|
||||
},
|
||||
}).toMinimalSpec().fieldAttrs
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"test1": Object {
|
||||
"customLabel": "test11",
|
||||
},
|
||||
}
|
||||
`);
|
||||
|
||||
expect(
|
||||
create('test', {
|
||||
id: 'test',
|
||||
title: 'test*',
|
||||
fields: fieldsMap,
|
||||
fieldAttrs: {
|
||||
test1: {
|
||||
count: 11,
|
||||
customLabel: 'test11',
|
||||
},
|
||||
test2: {
|
||||
customLabel: 'test12',
|
||||
},
|
||||
test3: {
|
||||
count: 30,
|
||||
},
|
||||
},
|
||||
}).toMinimalSpec().fieldAttrs
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"test1": Object {
|
||||
"customLabel": "test11",
|
||||
},
|
||||
"test2": Object {
|
||||
"customLabel": "test12",
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -15,7 +15,7 @@ import type {
|
|||
} from '@kbn/field-formats-plugin/common';
|
||||
import { castEsToKbnFieldTypeName, ES_FIELD_TYPES, KBN_FIELD_TYPES } from '@kbn/field-types';
|
||||
import { CharacterNotAllowedInField } from '@kbn/kibana-utils-plugin/common';
|
||||
import { cloneDeep, each, reject } from 'lodash';
|
||||
import { cloneDeep, each, mapValues, omit, pickBy, reject } from 'lodash';
|
||||
import type { DataViewAttributes, FieldAttrs, FieldAttrSet } from '..';
|
||||
import type { DataViewField, IIndexPatternFieldList } from '../fields';
|
||||
import { fieldList } from '../fields';
|
||||
|
@ -332,6 +332,28 @@ export class DataView implements DataViewBase {
|
|||
return Object.fromEntries(Object.entries(spec).filter(([, v]) => typeof v !== 'undefined'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a minimal static representation of the data view. Fields and popularity scores will be omitted.
|
||||
*/
|
||||
public toMinimalSpec(): Omit<DataViewSpec, 'fields'> {
|
||||
// removes `fields`
|
||||
const dataViewSpec = this.toSpec(false);
|
||||
|
||||
if (dataViewSpec.fieldAttrs) {
|
||||
// removes `count` props (popularity scores) from `fieldAttrs`
|
||||
dataViewSpec.fieldAttrs = pickBy(
|
||||
mapValues(dataViewSpec.fieldAttrs, (fieldAttrs) => omit(fieldAttrs, 'count')),
|
||||
(trimmedFieldAttrs) => Object.keys(trimmedFieldAttrs).length > 0
|
||||
);
|
||||
|
||||
if (Object.keys(dataViewSpec.fieldAttrs).length === 0) {
|
||||
dataViewSpec.fieldAttrs = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
return dataViewSpec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the source filtering configuration for that index.
|
||||
*/
|
||||
|
|
|
@ -146,7 +146,7 @@ export const getTopNavLinks = ({
|
|||
...(savedSearch.id ? { savedSearchId: savedSearch.id } : {}),
|
||||
...(dataView?.isPersisted()
|
||||
? { dataViewId: dataView?.id }
|
||||
: { dataViewSpec: dataView?.toSpec() }),
|
||||
: { dataViewSpec: dataView?.toMinimalSpec() }),
|
||||
filters,
|
||||
timeRange,
|
||||
refreshInterval,
|
||||
|
|
|
@ -522,7 +522,7 @@ describe('Test discover state actions', () => {
|
|||
timeFieldName: 'mock-time-field-name',
|
||||
};
|
||||
const dataViewsCreateMock = discoverServiceMock.dataViews.create as jest.Mock;
|
||||
dataViewsCreateMock.mockImplementation(() => ({
|
||||
dataViewsCreateMock.mockImplementationOnce(() => ({
|
||||
...dataViewMock,
|
||||
...dataViewSpecMock,
|
||||
isPersisted: () => false,
|
||||
|
|
|
@ -540,6 +540,6 @@ function createUrlGeneratorState({
|
|||
viewMode: appState.viewMode,
|
||||
hideAggregatedPreview: appState.hideAggregatedPreview,
|
||||
breakdownField: appState.breakdownField,
|
||||
dataViewSpec: !dataView?.isPersisted() ? dataView?.toSpec(false) : undefined,
|
||||
dataViewSpec: !dataView?.isPersisted() ? dataView?.toMinimalSpec() : undefined,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { omit, pickBy, mapValues } from 'lodash';
|
||||
import { buildRangeFilter, Filter } from '@kbn/es-query';
|
||||
import {
|
||||
DataView,
|
||||
|
@ -221,19 +220,5 @@ function updateFilterReferences(filters: Filter[], fromDataView: string, toDataV
|
|||
export function getSmallerDataViewSpec(
|
||||
dataView: DataView
|
||||
): DiscoverAppLocatorParams['dataViewSpec'] {
|
||||
const dataViewSpec = dataView.toSpec(false);
|
||||
|
||||
if (dataViewSpec.fieldAttrs) {
|
||||
// remove `count` props
|
||||
dataViewSpec.fieldAttrs = pickBy(
|
||||
mapValues(dataViewSpec.fieldAttrs, (fieldAttrs) => omit(fieldAttrs, 'count')),
|
||||
(trimmedFieldAttrs) => Object.keys(trimmedFieldAttrs).length > 0
|
||||
);
|
||||
|
||||
if (Object.keys(dataViewSpec.fieldAttrs).length === 0) {
|
||||
dataViewSpec.fieldAttrs = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
return dataViewSpec;
|
||||
return dataView.toMinimalSpec();
|
||||
}
|
||||
|
|
|
@ -14,6 +14,8 @@ import {
|
|||
AlertInstanceMock,
|
||||
} from '@kbn/alerting-plugin/server/mocks';
|
||||
import { loggingSystemMock } from '@kbn/core/server/mocks';
|
||||
import type { DataViewSpec } from '@kbn/data-views-plugin/common';
|
||||
import { createStubDataView } from '@kbn/data-views-plugin/common/data_view.stub';
|
||||
import { getRuleType } from './rule_type';
|
||||
import { EsQueryRuleParams, EsQueryRuleState } from './rule_type_params';
|
||||
import { ActionContext } from './action_context';
|
||||
|
@ -512,32 +514,31 @@ describe('ruleType', () => {
|
|||
});
|
||||
|
||||
describe('search source query', () => {
|
||||
const dataViewMock = {
|
||||
id: 'test-id',
|
||||
title: 'test-title',
|
||||
timeFieldName: 'time-field',
|
||||
fields: [
|
||||
{
|
||||
name: 'message',
|
||||
type: 'string',
|
||||
displayName: 'message',
|
||||
scripted: false,
|
||||
filterable: false,
|
||||
aggregatable: false,
|
||||
const dataViewMock = createStubDataView({
|
||||
spec: {
|
||||
id: 'test-id',
|
||||
title: 'test-title',
|
||||
timeFieldName: 'time-field',
|
||||
fields: {
|
||||
message: {
|
||||
name: 'message',
|
||||
type: 'string',
|
||||
scripted: false,
|
||||
searchable: false,
|
||||
aggregatable: false,
|
||||
readFromDocValues: false,
|
||||
},
|
||||
timestamp: {
|
||||
name: 'timestamp',
|
||||
type: 'date',
|
||||
scripted: false,
|
||||
searchable: true,
|
||||
aggregatable: false,
|
||||
readFromDocValues: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'timestamp',
|
||||
type: 'date',
|
||||
displayName: 'timestamp',
|
||||
scripted: false,
|
||||
filterable: false,
|
||||
aggregatable: false,
|
||||
},
|
||||
],
|
||||
toSpec: () => {
|
||||
return { id: 'test-id', title: 'test-title', timeFieldName: 'time-field' };
|
||||
},
|
||||
};
|
||||
});
|
||||
const defaultParams: OnlySearchSourceRuleParams = {
|
||||
size: 100,
|
||||
timeWindowSize: 5,
|
||||
|
@ -583,9 +584,9 @@ describe('ruleType', () => {
|
|||
const searchResult: ESSearchResponse<unknown, {}> = generateResults([]);
|
||||
const ruleServices: RuleExecutorServicesMock = alertsMock.createRuleExecutorServices();
|
||||
|
||||
(ruleServices.dataViews.create as jest.Mock).mockResolvedValueOnce({
|
||||
toSpec: () => dataViewMock.toSpec(),
|
||||
});
|
||||
(ruleServices.dataViews.create as jest.Mock).mockImplementationOnce((spec: DataViewSpec) =>
|
||||
createStubDataView({ spec })
|
||||
);
|
||||
(searchSourceInstanceMock.getField as jest.Mock).mockImplementation((name: string) => {
|
||||
if (name === 'index') {
|
||||
return dataViewMock;
|
||||
|
@ -620,9 +621,9 @@ describe('ruleType', () => {
|
|||
const params = { ...defaultParams, thresholdComparator: Comparator.GT_OR_EQ, threshold: [3] };
|
||||
const ruleServices: RuleExecutorServicesMock = alertsMock.createRuleExecutorServices();
|
||||
|
||||
(ruleServices.dataViews.create as jest.Mock).mockResolvedValueOnce({
|
||||
toSpec: () => dataViewMock.toSpec(),
|
||||
});
|
||||
(ruleServices.dataViews.create as jest.Mock).mockImplementationOnce((spec: DataViewSpec) =>
|
||||
createStubDataView({ spec })
|
||||
);
|
||||
(searchSourceInstanceMock.getField as jest.Mock).mockImplementation((name: string) => {
|
||||
if (name === 'index') {
|
||||
return dataViewMock;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue