mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
Add add missing saved object reference handling for searchSourceJSON filter attribute (#29840)
* Add missing references for searchSourceJSON filter * Add tests for searchSourceJSON filter, more tests for index attribute as well * Define indexRefName once * Fix broken test, avoid mutating searchSourceFields * Fix bug in code change
This commit is contained in:
parent
3ccf6793df
commit
6b74470eae
4 changed files with 367 additions and 26 deletions
|
@ -31,16 +31,29 @@ function migrateIndexPattern(doc) {
|
|||
// Let it go, the data is invalid and we'll leave it as is
|
||||
return;
|
||||
}
|
||||
if (!searchSource.index) {
|
||||
return;
|
||||
if (searchSource.index) {
|
||||
searchSource.indexRefName = 'kibanaSavedObjectMeta.searchSourceJSON.index';
|
||||
doc.references.push({
|
||||
name: searchSource.indexRefName,
|
||||
type: 'index-pattern',
|
||||
id: searchSource.index,
|
||||
});
|
||||
delete searchSource.index;
|
||||
}
|
||||
if (searchSource.filter) {
|
||||
searchSource.filter.forEach((filterRow, i) => {
|
||||
if (!filterRow.meta || !filterRow.meta.index) {
|
||||
return;
|
||||
}
|
||||
filterRow.meta.indexRefName = `kibanaSavedObjectMeta.searchSourceJSON.filter[${i}].meta.index`;
|
||||
doc.references.push({
|
||||
name: filterRow.meta.indexRefName,
|
||||
type: 'index-pattern',
|
||||
id: filterRow.meta.index,
|
||||
});
|
||||
delete filterRow.meta.index;
|
||||
});
|
||||
}
|
||||
doc.references.push({
|
||||
name: 'kibanaSavedObjectMeta.searchSourceJSON.index',
|
||||
type: 'index-pattern',
|
||||
id: searchSource.index,
|
||||
});
|
||||
searchSource.indexRefName = 'kibanaSavedObjectMeta.searchSourceJSON.index';
|
||||
delete searchSource.index;
|
||||
doc.attributes.kibanaSavedObjectMeta.searchSourceJSON = JSON.stringify(searchSource);
|
||||
}
|
||||
|
||||
|
|
|
@ -189,7 +189,7 @@ Object {
|
|||
`);
|
||||
});
|
||||
|
||||
it('skips error when "index" is missing from searchSourceJSON', () => {
|
||||
it('skips error when "index" and "filter" is missing from searchSourceJSON', () => {
|
||||
const doc = {
|
||||
id: '1',
|
||||
type: 'visualization',
|
||||
|
@ -264,6 +264,55 @@ Object {
|
|||
`);
|
||||
});
|
||||
|
||||
it('extracts index patterns from the filter', () => {
|
||||
const doc = {
|
||||
id: '1',
|
||||
type: 'visualization',
|
||||
attributes: {
|
||||
visState: '{}',
|
||||
kibanaSavedObjectMeta: {
|
||||
searchSourceJSON: JSON.stringify({
|
||||
bar: true,
|
||||
filter: [
|
||||
{
|
||||
meta: { index: 'my-index', foo: true },
|
||||
},
|
||||
],
|
||||
}),
|
||||
},
|
||||
savedSearchId: '123',
|
||||
},
|
||||
};
|
||||
const migratedDoc = migrate(doc);
|
||||
/* eslint-disable max-len */
|
||||
expect(migratedDoc).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"kibanaSavedObjectMeta": Object {
|
||||
"searchSourceJSON": "{\\"bar\\":true,\\"filter\\":[{\\"meta\\":{\\"foo\\":true,\\"indexRefName\\":\\"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index\\"}}]}",
|
||||
},
|
||||
"savedSearchRefName": "search_0",
|
||||
"visState": "{}",
|
||||
},
|
||||
"id": "1",
|
||||
"references": Array [
|
||||
Object {
|
||||
"id": "my-index",
|
||||
"name": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index",
|
||||
"type": "index-pattern",
|
||||
},
|
||||
Object {
|
||||
"id": "123",
|
||||
"name": "search_0",
|
||||
"type": "search",
|
||||
},
|
||||
],
|
||||
"type": "visualization",
|
||||
}
|
||||
`);
|
||||
/* eslint-enable max-len */
|
||||
});
|
||||
|
||||
it('skips extracting savedSearchId when missing', () => {
|
||||
const doc = {
|
||||
id: '1',
|
||||
|
@ -634,7 +683,7 @@ Object {
|
|||
`);
|
||||
});
|
||||
|
||||
test('skips error when "index" is missing from searchSourceJSON', () => {
|
||||
test('skips error when "index" and "filter" is missing from searchSourceJSON', () => {
|
||||
const doc = {
|
||||
id: '1',
|
||||
type: 'dashboard',
|
||||
|
@ -717,6 +766,62 @@ Object {
|
|||
`);
|
||||
});
|
||||
|
||||
test('extracts index patterns from filter', () => {
|
||||
const doc = {
|
||||
id: '1',
|
||||
type: 'dashboard',
|
||||
attributes: {
|
||||
kibanaSavedObjectMeta: {
|
||||
searchSourceJSON: JSON.stringify({
|
||||
bar: true,
|
||||
filter: [
|
||||
{
|
||||
meta: {
|
||||
foo: true,
|
||||
index: 'my-index',
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
},
|
||||
panelsJSON:
|
||||
'[{"id":"1","type":"visualization","foo":true},{"id":"2","type":"visualization","bar":true}]',
|
||||
},
|
||||
};
|
||||
const migratedDoc = migration(doc);
|
||||
/* eslint-disable max-len */
|
||||
expect(migratedDoc).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"kibanaSavedObjectMeta": Object {
|
||||
"searchSourceJSON": "{\\"bar\\":true,\\"filter\\":[{\\"meta\\":{\\"foo\\":true,\\"indexRefName\\":\\"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index\\"}}]}",
|
||||
},
|
||||
"panelsJSON": "[{\\"foo\\":true,\\"panelRefName\\":\\"panel_0\\"},{\\"bar\\":true,\\"panelRefName\\":\\"panel_1\\"}]",
|
||||
},
|
||||
"id": "1",
|
||||
"references": Array [
|
||||
Object {
|
||||
"id": "my-index",
|
||||
"name": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index",
|
||||
"type": "index-pattern",
|
||||
},
|
||||
Object {
|
||||
"id": "1",
|
||||
"name": "panel_0",
|
||||
"type": "visualization",
|
||||
},
|
||||
Object {
|
||||
"id": "2",
|
||||
"name": "panel_1",
|
||||
"type": "visualization",
|
||||
},
|
||||
],
|
||||
"type": "dashboard",
|
||||
}
|
||||
`);
|
||||
/* eslint-enable max-len */
|
||||
});
|
||||
|
||||
test('skips error when panelsJSON is not a string', () => {
|
||||
const doc = {
|
||||
id: '1',
|
||||
|
@ -950,7 +1055,7 @@ Object {
|
|||
`);
|
||||
});
|
||||
|
||||
test('skips error when "index" is missing from searchSourceJSON', () => {
|
||||
test('skips error when "index" and "filter" is missing from searchSourceJSON', () => {
|
||||
const doc = {
|
||||
id: '123',
|
||||
type: 'search',
|
||||
|
@ -1009,5 +1114,50 @@ Object {
|
|||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('extracts index patterns from filter', () => {
|
||||
const doc = {
|
||||
id: '123',
|
||||
type: 'search',
|
||||
attributes: {
|
||||
foo: true,
|
||||
kibanaSavedObjectMeta: {
|
||||
searchSourceJSON: JSON.stringify({
|
||||
bar: true,
|
||||
filter: [
|
||||
{
|
||||
meta: {
|
||||
foo: true,
|
||||
index: 'my-index',
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
},
|
||||
},
|
||||
};
|
||||
const migratedDoc = migration(doc);
|
||||
/* eslint-disable max-len */
|
||||
expect(migratedDoc).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"foo": true,
|
||||
"kibanaSavedObjectMeta": Object {
|
||||
"searchSourceJSON": "{\\"bar\\":true,\\"filter\\":[{\\"meta\\":{\\"foo\\":true,\\"indexRefName\\":\\"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index\\"}}]}",
|
||||
},
|
||||
},
|
||||
"id": "123",
|
||||
"references": Array [
|
||||
Object {
|
||||
"id": "my-index",
|
||||
"name": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index",
|
||||
"type": "index-pattern",
|
||||
},
|
||||
],
|
||||
"type": "search",
|
||||
}
|
||||
`);
|
||||
/* eslint-enable max-len */
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -292,13 +292,16 @@ describe('Saved Object', function () {
|
|||
});
|
||||
});
|
||||
|
||||
describe('with extractReferences', () => {
|
||||
it('calls the function', async () => {
|
||||
describe('to extract references', () => {
|
||||
it('when "extractReferences" function when passed in', async () => {
|
||||
const id = '123';
|
||||
stubESResponse(getMockedDocResponse('id'));
|
||||
let extractReferencesCallCount = 0;
|
||||
stubESResponse(getMockedDocResponse(id));
|
||||
const extractReferences = ({ attributes, references }) => {
|
||||
extractReferencesCallCount++;
|
||||
references.push({
|
||||
name: 'test',
|
||||
type: 'index-pattern',
|
||||
id: 'my-index',
|
||||
});
|
||||
return { attributes, references };
|
||||
};
|
||||
return createInitializedSavedObject({ type: 'dashboard', extractReferences })
|
||||
|
@ -310,10 +313,95 @@ describe('Saved Object', function () {
|
|||
type: 'dashboard',
|
||||
});
|
||||
});
|
||||
return savedObject.save();
|
||||
})
|
||||
.then(() => {
|
||||
expect(extractReferencesCallCount).to.be(1);
|
||||
return savedObject
|
||||
.save()
|
||||
.then(() => {
|
||||
const { references } = savedObjectsClientStub.create.getCall(0).args[2];
|
||||
expect(references).to.have.length(1);
|
||||
expect(references[0]).to.eql({
|
||||
name: 'test',
|
||||
type: 'index-pattern',
|
||||
id: 'my-index',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('when index exists in searchSourceJSON', () => {
|
||||
const id = '123';
|
||||
stubESResponse(getMockedDocResponse(id));
|
||||
return createInitializedSavedObject({ type: 'dashboard', searchSource: true })
|
||||
.then((savedObject) => {
|
||||
sinon.stub(savedObjectsClientStub, 'create').callsFake(() => {
|
||||
return BluebirdPromise.resolve({
|
||||
id,
|
||||
version: 2,
|
||||
type: 'dashboard',
|
||||
});
|
||||
});
|
||||
savedObject.searchSource.setField('index', new IndexPattern('my-index', null, []));
|
||||
return savedObject
|
||||
.save()
|
||||
.then(() => {
|
||||
expect(savedObjectsClientStub.create.getCall(0).args[1]).to.eql({
|
||||
kibanaSavedObjectMeta: {
|
||||
searchSourceJSON: JSON.stringify({
|
||||
indexRefName: 'kibanaSavedObjectMeta.searchSourceJSON.index',
|
||||
}),
|
||||
},
|
||||
});
|
||||
const { references } = savedObjectsClientStub.create.getCall(0).args[2];
|
||||
expect(references).to.have.length(1);
|
||||
expect(references[0]).to.eql({
|
||||
name: 'kibanaSavedObjectMeta.searchSourceJSON.index',
|
||||
type: 'index-pattern',
|
||||
id: 'my-index',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('when indexes exists in filter of searchSourceJSON', () => {
|
||||
const id = '123';
|
||||
stubESResponse(getMockedDocResponse(id));
|
||||
return createInitializedSavedObject({ type: 'dashboard', searchSource: true })
|
||||
.then((savedObject) => {
|
||||
sinon.stub(savedObjectsClientStub, 'create').callsFake(() => {
|
||||
return BluebirdPromise.resolve({
|
||||
id,
|
||||
version: 2,
|
||||
type: 'dashboard',
|
||||
});
|
||||
});
|
||||
savedObject.searchSource.setField('filter', [{
|
||||
meta: {
|
||||
index: 'my-index',
|
||||
}
|
||||
}]);
|
||||
return savedObject
|
||||
.save()
|
||||
.then(() => {
|
||||
expect(savedObjectsClientStub.create.getCall(0).args[1]).to.eql({
|
||||
kibanaSavedObjectMeta: {
|
||||
searchSourceJSON: JSON.stringify({
|
||||
filter: [
|
||||
{
|
||||
meta: {
|
||||
indexRefName: 'kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index',
|
||||
}
|
||||
}
|
||||
],
|
||||
}),
|
||||
},
|
||||
});
|
||||
const { references } = savedObjectsClientStub.create.getCall(0).args[2];
|
||||
expect(references).to.have.length(1);
|
||||
expect(references[0]).to.eql({
|
||||
name: 'kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index',
|
||||
type: 'index-pattern',
|
||||
id: 'my-index',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -504,6 +592,54 @@ describe('Saved Object', function () {
|
|||
expect(injectReferences).to.have.property('calledOnce', true);
|
||||
});
|
||||
});
|
||||
|
||||
it('injects references from searchSourceJSON', async () => {
|
||||
const savedObject = new SavedObject({ type: 'dashboard', searchSource: true });
|
||||
return savedObject
|
||||
.init()
|
||||
.then(() => {
|
||||
const response = {
|
||||
found: true,
|
||||
_source: {
|
||||
kibanaSavedObjectMeta: {
|
||||
searchSourceJSON: JSON.stringify({
|
||||
indexRefName: 'kibanaSavedObjectMeta.searchSourceJSON.index',
|
||||
filter: [
|
||||
{
|
||||
meta: {
|
||||
indexRefName: 'kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index',
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
},
|
||||
},
|
||||
references: [
|
||||
{
|
||||
name: 'kibanaSavedObjectMeta.searchSourceJSON.index',
|
||||
type: 'index-pattern',
|
||||
id: 'my-index-1',
|
||||
},
|
||||
{
|
||||
name: 'kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index',
|
||||
type: 'index-pattern',
|
||||
id: 'my-index-2',
|
||||
},
|
||||
],
|
||||
};
|
||||
savedObject.applyESResp(response);
|
||||
expect(savedObject.searchSource.getFields()).to.eql({
|
||||
index: 'my-index-1',
|
||||
filter: [
|
||||
{
|
||||
meta: {
|
||||
index: 'my-index-2',
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe ('config', function () {
|
||||
|
|
|
@ -148,6 +148,20 @@ export function SavedObjectProvider(Promise, Private, Notifier, confirmModalProm
|
|||
delete searchSourceValues.indexRefName;
|
||||
}
|
||||
|
||||
if (searchSourceValues.filter) {
|
||||
searchSourceValues.filter.forEach((filterRow) => {
|
||||
if (!filterRow.meta || !filterRow.meta.indexRefName) {
|
||||
return;
|
||||
}
|
||||
const reference = references.find(reference => reference.name === filterRow.meta.indexRefName);
|
||||
if (!reference) {
|
||||
throw new Error(`Could not find reference for ${filterRow.meta.indexRefName} on ${this.getEsType()}`);
|
||||
}
|
||||
filterRow.meta.index = reference.id;
|
||||
delete filterRow.meta.indexRefName;
|
||||
});
|
||||
}
|
||||
|
||||
const searchSourceFields = this.searchSource.getFields();
|
||||
const fnProps = _.transform(searchSourceFields, function (dynamic, val, name) {
|
||||
if (_.isFunction(val)) dynamic[name] = val;
|
||||
|
@ -296,16 +310,44 @@ export function SavedObjectProvider(Promise, Private, Notifier, confirmModalProm
|
|||
});
|
||||
|
||||
if (this.searchSource) {
|
||||
const searchSourceFields = _.omit(this.searchSource.getFields(), ['sort', 'size']);
|
||||
let searchSourceFields = _.omit(this.searchSource.getFields(), ['sort', 'size']);
|
||||
if (searchSourceFields.index) {
|
||||
const indexId = searchSourceFields.index;
|
||||
searchSourceFields.indexRefName = 'kibanaSavedObjectMeta.searchSourceJSON.index';
|
||||
const { id: indexId } = searchSourceFields.index;
|
||||
const refName = 'kibanaSavedObjectMeta.searchSourceJSON.index';
|
||||
references.push({
|
||||
name: 'kibanaSavedObjectMeta.searchSourceJSON.index',
|
||||
name: refName,
|
||||
type: 'index-pattern',
|
||||
id: indexId,
|
||||
});
|
||||
delete searchSourceFields.index;
|
||||
searchSourceFields = {
|
||||
...searchSourceFields,
|
||||
indexRefName: refName,
|
||||
index: undefined,
|
||||
};
|
||||
}
|
||||
if (searchSourceFields.filter) {
|
||||
searchSourceFields = {
|
||||
...searchSourceFields,
|
||||
filter: searchSourceFields.filter.map((filterRow, i) => {
|
||||
if (!filterRow.meta || !filterRow.meta.index) {
|
||||
return filterRow;
|
||||
}
|
||||
const refName = `kibanaSavedObjectMeta.searchSourceJSON.filter[${i}].meta.index`;
|
||||
references.push({
|
||||
name: refName,
|
||||
type: 'index-pattern',
|
||||
id: filterRow.meta.index,
|
||||
});
|
||||
return {
|
||||
...filterRow,
|
||||
meta: {
|
||||
...filterRow.meta,
|
||||
indexRefName: refName,
|
||||
index: undefined,
|
||||
}
|
||||
};
|
||||
}),
|
||||
};
|
||||
}
|
||||
attributes.kibanaSavedObjectMeta = {
|
||||
searchSourceJSON: angular.toJson(searchSourceFields)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue