diff --git a/src/legacy/core_plugins/kibana/migrations.js b/src/legacy/core_plugins/kibana/migrations.js index 744671dbbe8fd..2eb418660f7ab 100644 --- a/src/legacy/core_plugins/kibana/migrations.js +++ b/src/legacy/core_plugins/kibana/migrations.js @@ -78,6 +78,33 @@ export const migrations = { delete doc.attributes.savedSearchId; } + // Migrate controls + const visStateJSON = get(doc, 'attributes.visState'); + if (visStateJSON) { + let visState; + try { + visState = JSON.parse(visStateJSON); + } catch (e) { + // Let it go, the data is invalid and we'll leave it as is + } + if (visState) { + const controls = get(visState, 'params.controls') || []; + controls.forEach((control, i) => { + if (!control.indexPattern) { + return; + } + control.indexPatternRefName = `control_${i}_index_pattern`; + doc.references.push({ + name: control.indexPatternRefName, + type: 'index-pattern', + id: control.indexPattern, + }); + delete control.indexPattern; + }); + doc.attributes.visState = JSON.stringify(visState); + } + } + // Migrate table splits try { const visState = JSON.parse(doc.attributes.visState); diff --git a/src/legacy/core_plugins/kibana/migrations.test.js b/src/legacy/core_plugins/kibana/migrations.test.js index f7f62807afd51..f06e6e327f83c 100644 --- a/src/legacy/core_plugins/kibana/migrations.test.js +++ b/src/legacy/core_plugins/kibana/migrations.test.js @@ -313,6 +313,50 @@ Object { /* eslint-enable max-len */ }); + it('extracts index patterns from controls', () => { + const doc = { + id: '1', + type: 'visualization', + attributes: { + foo: true, + visState: JSON.stringify({ + bar: false, + params: { + controls: [ + { + bar: true, + indexPattern: 'pattern*', + }, + { + foo: true, + }, + ], + }, + }), + }, + }; + const migratedDoc = migrate(doc); + /* eslint-disable max-len */ + expect(migratedDoc).toMatchInlineSnapshot(` +Object { + "attributes": Object { + "foo": true, + "visState": "{\\"bar\\":false,\\"params\\":{\\"controls\\":[{\\"bar\\":true,\\"indexPatternRefName\\":\\"control_0_index_pattern\\"},{\\"foo\\":true}]}}", + }, + "id": "1", + "references": Array [ + Object { + "id": "pattern*", + "name": "control_0_index_pattern", + "type": "index-pattern", + }, + ], + "type": "visualization", +} +`); + /* eslint-enable max-len */ + }); + it('skips extracting savedSearchId when missing', () => { const doc = { id: '1', @@ -1157,7 +1201,7 @@ Object { "type": "search", } `); - /* eslint-enable max-len */ + /* eslint-enable max-len */ }); }); }); diff --git a/src/legacy/core_plugins/kibana/public/visualize/saved_visualizations/saved_visualization_references.js b/src/legacy/core_plugins/kibana/public/visualize/saved_visualizations/saved_visualization_references.js index 953c32e58e1b7..2e2a9eb5d0661 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/saved_visualizations/saved_visualization_references.js +++ b/src/legacy/core_plugins/kibana/public/visualize/saved_visualizations/saved_visualization_references.js @@ -18,34 +18,66 @@ */ export function extractReferences({ attributes, references = [] }) { - if (!attributes.savedSearchId) { - return { attributes, references }; + const updatedAttributes = { ...attributes }; + const updatedReferences = [...references]; + + // Extract saved search + if (updatedAttributes.savedSearchId) { + updatedReferences.push({ + name: 'search_0', + type: 'search', + id: updatedAttributes.savedSearchId, + }); + delete updatedAttributes.savedSearchId; + updatedAttributes.savedSearchRefName = 'search_0'; + } + + // Extract index patterns from controls + if (updatedAttributes.visState) { + const visState = JSON.parse(updatedAttributes.visState); + const controls = visState.params && visState.params.controls || []; + controls.forEach((control, i) => { + if (!control.indexPattern) { + return; + } + control.indexPatternRefName = `control_${i}_index_pattern`; + updatedReferences.push({ + name: control.indexPatternRefName, + type: 'index-pattern', + id: control.indexPattern, + }); + delete control.indexPattern; + }); + updatedAttributes.visState = JSON.stringify(visState); } + return { - references: [ - ...references, - { - type: 'search', - name: 'search_0', - id: attributes.savedSearchId, - }, - ], - attributes: { - ...attributes, - savedSearchId: undefined, - savedSearchRefName: 'search_0', - }, + references: updatedReferences, + attributes: updatedAttributes, }; } export function injectReferences(savedObject, references) { - if (!savedObject.savedSearchRefName) { - return; + if (savedObject.savedSearchRefName) { + const savedSearchReference = references.find(reference => reference.name === savedObject.savedSearchRefName); + if (!savedSearchReference) { + throw new Error(`Could not find saved search reference "${savedObject.savedSearchRefName}"`); + } + savedObject.savedSearchId = savedSearchReference.id; + delete savedObject.savedSearchRefName; } - const reference = references.find(reference => reference.name === savedObject.savedSearchRefName); - if (!reference) { - throw new Error(`Could not find reference "${savedObject.savedSearchRefName}"`); + if (savedObject.visState) { + const controls = (savedObject.visState.params && savedObject.visState.params.controls) || []; + controls.forEach((control) => { + if (!control.indexPatternRefName) { + return; + } + const reference = references.find(reference => reference.name === control.indexPatternRefName); + if (!reference) { + throw new Error (`Could not find index pattern reference "${control.indexPatternRefName}"`); + } + control.indexPattern = reference.id; + delete control.indexPatternRefName; + }); } - savedObject.savedSearchId = reference.id; - delete savedObject.savedSearchRefName; } diff --git a/src/legacy/core_plugins/kibana/public/visualize/saved_visualizations/saved_visualization_references.test.js b/src/legacy/core_plugins/kibana/public/visualize/saved_visualizations/saved_visualization_references.test.js index be9375dc33e56..df17e9c1bb30a 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/saved_visualizations/saved_visualization_references.test.js +++ b/src/legacy/core_plugins/kibana/public/visualize/saved_visualizations/saved_visualization_references.test.js @@ -51,7 +51,6 @@ Object { Object { "attributes": Object { "foo": true, - "savedSearchId": undefined, "savedSearchRefName": "search_0", }, "references": Array [ @@ -64,6 +63,46 @@ Object { } `); }); + + test('extracts references from controls', () => { + const doc = { + id: '1', + attributes: { + foo: true, + visState: JSON.stringify({ + params: { + controls: [ + { + bar: true, + indexPattern: 'pattern*', + }, + { + bar: false, + }, + ], + }, + }), + }, + }; + const updatedDoc = extractReferences(doc); + /* eslint-disable max-len */ + expect(updatedDoc).toMatchInlineSnapshot(` +Object { + "attributes": Object { + "foo": true, + "visState": "{\\"params\\":{\\"controls\\":[{\\"bar\\":true,\\"indexPatternRefName\\":\\"control_0_index_pattern\\"},{\\"bar\\":false}]}}", + }, + "references": Array [ + Object { + "id": "pattern*", + "name": "control_0_index_pattern", + "type": "index-pattern", + }, + ], +} +`); + /* eslint-enable max-len */ + }); }); describe('injectReferences', () => { @@ -86,6 +125,19 @@ Object { id: '1', foo: true, savedSearchRefName: 'search_0', + visState: { + params: { + controls: [ + { + foo: true, + indexPatternRefName: 'control_0_index_pattern', + }, + { + foo: false, + }, + ], + }, + }, }; const references = [ { @@ -93,6 +145,11 @@ Object { type: 'search', id: '123', }, + { + name: 'control_0_index_pattern', + type: 'index-pattern', + id: 'pattern*', + }, ]; injectReferences(context, references); expect(context).toMatchInlineSnapshot(` @@ -100,18 +157,50 @@ Object { "foo": true, "id": "1", "savedSearchId": "123", + "visState": Object { + "params": Object { + "controls": Array [ + Object { + "foo": true, + "indexPattern": "pattern*", + }, + Object { + "foo": false, + }, + ], + }, + }, } `); }); - test(`fails when it can't find the reference in the array`, () => { + test(`fails when it can't find the saved search reference in the array`, () => { const context = { id: '1', foo: true, savedSearchRefName: 'search_0', }; expect(() => injectReferences(context, [])).toThrowErrorMatchingInlineSnapshot( - `"Could not find reference \\"search_0\\""` + `"Could not find saved search reference \\"search_0\\""` + ); + }); + + test(`fails when it can't find the index pattern reference in the array`, () => { + const context = { + id: '1', + visState: { + params: { + controls: [ + { + foo: true, + indexPatternRefName: 'control_0_index_pattern', + }, + ], + }, + }, + }; + expect(() => injectReferences(context, [])).toThrowErrorMatchingInlineSnapshot( + `"Could not find index pattern reference \\"control_0_index_pattern\\""` ); }); });