[SOM] Preserve saved object references when saving the object (#66584)

* create field for references and add comments

* add FTR test

* remove comments

* address comments

* use real reference in dataset and assert against it.
This commit is contained in:
Pierre Gayvallet 2020-05-16 09:08:45 +02:00 committed by GitHub
parent 74611e742d
commit 61936a1870
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 143 additions and 5 deletions

View file

@ -59,6 +59,11 @@ describe('createFieldList', () => {
"type": "boolean",
"value": true,
},
Object {
"name": "references",
"type": "array",
"value": "[]",
},
]
`);
});
@ -76,6 +81,11 @@ describe('createFieldList', () => {
\\"data\\": \\"value\\"
}",
},
Object {
"name": "references",
"type": "array",
"value": "[]",
},
]
`);
});
@ -93,6 +103,48 @@ describe('createFieldList', () => {
1,
2,
3
]",
},
Object {
"name": "references",
"type": "array",
"value": "[]",
},
]
`);
});
it(`generates a field for the object's references`, () => {
const obj = createObject(
{
someString: 'foo',
},
[
{ id: 'ref1', type: 'type', name: 'Ref 1' },
{ id: 'ref12', type: 'other-type', name: 'Ref 2' },
]
);
expect(createFieldList(obj)).toMatchInlineSnapshot(`
Array [
Object {
"name": "someString",
"type": "text",
"value": "foo",
},
Object {
"name": "references",
"type": "array",
"value": "[
{
\\"id\\": \\"ref1\\",
\\"type\\": \\"type\\",
\\"name\\": \\"Ref 1\\"
},
{
\\"id\\": \\"ref12\\",
\\"type\\": \\"other-type\\",
\\"name\\": \\"Ref 2\\"
}
]",
},
]
@ -126,6 +178,11 @@ describe('createFieldList', () => {
"type": "text",
"value": "B",
},
Object {
"name": "references",
"type": "array",
"value": "[]",
},
]
`);
});

View file

@ -29,12 +29,15 @@ export function createFieldList(
object: SimpleSavedObject,
service?: SavedObjectLoader
): ObjectField[] {
const fields = Object.entries(object.attributes as Record<string, any>).reduce(
let fields = Object.entries(object.attributes as Record<string, any>).reduce(
(objFields, [key, value]) => {
return [...objFields, ...recursiveCreateFields(key, value)];
return [...objFields, ...createFields(key, value)];
},
[] as ObjectField[]
);
// Special handling for references which isn't within "attributes"
fields = [...fields, ...createFields('references', object.references)];
if (service && (service as any).Class) {
addFieldsFromClass((service as any).Class, fields);
}
@ -53,7 +56,7 @@ export function createFieldList(
* @param {array} parents The parent keys to the field
* @returns {array}
*/
const recursiveCreateFields = (key: string, value: any, parents: string[] = []): ObjectField[] => {
const createFields = (key: string, value: any, parents: string[] = []): ObjectField[] => {
const path = [...parents, key];
if (path.length > maxRecursiveIterations) {
return [];
@ -78,7 +81,7 @@ const recursiveCreateFields = (key: string, value: any, parents: string[] = []):
} else if (isPlainObject(field.value)) {
let fields: ObjectField[] = [];
forOwn(field.value, (childValue, childKey) => {
fields = [...fields, ...recursiveCreateFields(childKey as string, childValue, path)];
fields = [...fields, ...createFields(childKey as string, childValue, path)];
});
return fields;
}

View file

@ -120,6 +120,7 @@ export class Field extends PureComponent<FieldProps> {
return (
<div data-test-subj={`savedObjects-editField-${name}`}>
<EuiCodeEditor
name={`savedObjects-editField-${name}-aceEditor`}
mode="json"
theme="textmate"
value={currentValue}

View file

@ -171,6 +171,7 @@ export class Form extends Component<FormProps, FormState> {
set(source, field.name, value);
});
// we extract the `references` field that does not belong to attributes
const { references, ...attributes } = source;
await onSave({ attributes, references });

View file

@ -26,6 +26,8 @@ export default function({ getPageObjects, getService }: FtrProviderContext) {
const esArchiver = getService('esArchiver');
const testSubjects = getService('testSubjects');
const PageObjects = getPageObjects(['common', 'settings']);
const browser = getService('browser');
const find = getService('find');
const setFieldValue = async (fieldName: string, value: string) => {
return testSubjects.setValue(`savedObjects-editField-${fieldName}`, value);
@ -35,6 +37,26 @@ export default function({ getPageObjects, getService }: FtrProviderContext) {
return testSubjects.getAttribute(`savedObjects-editField-${fieldName}`, 'value');
};
const setAceEditorFieldValue = async (fieldName: string, fieldValue: string) => {
const editorId = `savedObjects-editField-${fieldName}-aceEditor`;
await find.clickByCssSelector(`#${editorId}`);
return browser.execute(
(editor: string, value: string) => {
return (window as any).ace.edit(editor).setValue(value);
},
editorId,
fieldValue
);
};
const getAceEditorFieldValue = async (fieldName: string) => {
const editorId = `savedObjects-editField-${fieldName}-aceEditor`;
await find.clickByCssSelector(`#${editorId}`);
return browser.execute((editor: string) => {
return (window as any).ace.edit(editor).getValue() as string;
}, editorId);
};
const focusAndClickButton = async (buttonSubject: string) => {
const button = await testSubjects.find(buttonSubject);
await button.scrollIntoViewIfNecessary();
@ -99,5 +121,52 @@ export default function({ getPageObjects, getService }: FtrProviderContext) {
const objects = await PageObjects.settings.getSavedObjectsInTable();
expect(objects.includes('A Dashboard')).to.be(false);
});
it('preserves the object references when saving', async () => {
const testVisualizationUrl =
'/management/kibana/objects/savedVisualizations/75c3e060-1e7c-11e9-8488-65449e65d0ed';
const visualizationRefs = [
{
name: 'kibanaSavedObjectMeta.searchSourceJSON.index',
type: 'index-pattern',
id: 'logstash-*',
},
];
await PageObjects.settings.navigateTo();
await PageObjects.settings.clickKibanaSavedObjects();
const objects = await PageObjects.settings.getSavedObjectsInTable();
expect(objects.includes('A Pie')).to.be(true);
await PageObjects.common.navigateToActualUrl('kibana', testVisualizationUrl);
await testSubjects.existOrFail('savedObjectEditSave');
let displayedReferencesValue = await getAceEditorFieldValue('references');
expect(JSON.parse(displayedReferencesValue)).to.eql(visualizationRefs);
await focusAndClickButton('savedObjectEditSave');
await PageObjects.settings.getSavedObjectsInTable();
await PageObjects.common.navigateToActualUrl('kibana', testVisualizationUrl);
// Parsing to avoid random keys ordering issues in raw string comparison
expect(JSON.parse(await getAceEditorFieldValue('references'))).to.eql(visualizationRefs);
await setAceEditorFieldValue('references', JSON.stringify([], undefined, 2));
await focusAndClickButton('savedObjectEditSave');
await PageObjects.settings.getSavedObjectsInTable();
await PageObjects.common.navigateToActualUrl('kibana', testVisualizationUrl);
displayedReferencesValue = await getAceEditorFieldValue('references');
expect(JSON.parse(displayedReferencesValue)).to.eql([]);
});
});
}

View file

@ -38,7 +38,14 @@
},
"type": "visualization",
"updated_at": "2019-01-22T19:32:31.206Z"
}
},
"references" : [
{
"name" : "kibanaSavedObjectMeta.searchSourceJSON.index",
"type" : "index-pattern",
"id" : "logstash-*"
}
]
}
}