mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
merge conflicts (#20959)
This commit is contained in:
parent
d19079f6e3
commit
8ea7af9511
21 changed files with 1252 additions and 609 deletions
|
@ -11,16 +11,29 @@ exports[`FieldEditor should render create new scripted field correctly 1`] = `
|
|||
size="m"
|
||||
/>
|
||||
<eui-form>
|
||||
<scripting-disabled-callOut
|
||||
isVisible={false}
|
||||
/>
|
||||
<scripting-warning-callOut
|
||||
isVisible={true}
|
||||
/>
|
||||
<scripting-help-flyout
|
||||
isVisible={false}
|
||||
onClose={[Function]}
|
||||
/>
|
||||
<React.Fragment>
|
||||
<scripting-disabled-callOut
|
||||
isVisible={false}
|
||||
/>
|
||||
<scripting-warning-callOut
|
||||
isVisible={true}
|
||||
/>
|
||||
<ScriptingHelpFlyout
|
||||
executeScript={[Function]}
|
||||
indexPattern={
|
||||
Object {
|
||||
"fields": Array [
|
||||
Object {
|
||||
"name": "foobar",
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
isVisible={false}
|
||||
lang="painless"
|
||||
onClose={[Function]}
|
||||
/>
|
||||
</React.Fragment>
|
||||
<eui-form-row
|
||||
error="Name is required"
|
||||
helpText={null}
|
||||
|
@ -133,48 +146,64 @@ exports[`FieldEditor should render create new scripted field correctly 1`] = `
|
|||
onChange={[Function]}
|
||||
/>
|
||||
</eui-form-row>
|
||||
<eui-form-row
|
||||
error="Script is required"
|
||||
helpText={
|
||||
<eui-link
|
||||
onClick={[Function]}
|
||||
>
|
||||
Scripting help
|
||||
</eui-link>
|
||||
}
|
||||
isInvalid={true}
|
||||
label="Script"
|
||||
>
|
||||
<eui-textArea
|
||||
data-test-subj="editorFieldScript"
|
||||
<React.Fragment>
|
||||
<eui-form-row
|
||||
error="Script is required"
|
||||
isInvalid={true}
|
||||
onChange={[Function]}
|
||||
/>
|
||||
label="Script"
|
||||
>
|
||||
<eui-textArea
|
||||
data-test-subj="editorFieldScript"
|
||||
isInvalid={true}
|
||||
onChange={[Function]}
|
||||
/>
|
||||
</eui-form-row>
|
||||
<eui-form-row>
|
||||
<React.Fragment>
|
||||
<eui-text>
|
||||
Access fields with
|
||||
<code>
|
||||
doc['some_field'].value
|
||||
</code>
|
||||
.
|
||||
</eui-text>
|
||||
<br />
|
||||
<eui-link
|
||||
data-test-subj="scriptedFieldsHelpLink"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Get help with the syntax and preview the results of your script.
|
||||
</eui-link>
|
||||
</React.Fragment>
|
||||
</eui-form-row>
|
||||
</React.Fragment>
|
||||
<eui-form-row>
|
||||
<eui-flex-group>
|
||||
<eui-flex-item
|
||||
grow={false}
|
||||
>
|
||||
<eui-button
|
||||
data-test-subj="fieldSaveButton"
|
||||
fill={true}
|
||||
isDisabled={true}
|
||||
isLoading={false}
|
||||
onClick={[Function]}
|
||||
>
|
||||
Create field
|
||||
</eui-button>
|
||||
</eui-flex-item>
|
||||
<eui-flex-item
|
||||
grow={false}
|
||||
>
|
||||
<eui-button-empty
|
||||
data-test-subj="fieldCancelButton"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Cancel
|
||||
</eui-button-empty>
|
||||
</eui-flex-item>
|
||||
</eui-flex-group>
|
||||
</eui-form-row>
|
||||
<eui-flex-group>
|
||||
<eui-flex-item
|
||||
grow={false}
|
||||
>
|
||||
<eui-button
|
||||
data-test-subj="fieldSaveButton"
|
||||
fill={true}
|
||||
isDisabled={true}
|
||||
onClick={[Function]}
|
||||
>
|
||||
Create field
|
||||
</eui-button>
|
||||
</eui-flex-item>
|
||||
<eui-flex-item
|
||||
grow={false}
|
||||
>
|
||||
<eui-button-empty
|
||||
data-test-subj="fieldCancelButton"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Cancel
|
||||
</eui-button-empty>
|
||||
</eui-flex-item>
|
||||
</eui-flex-group>
|
||||
</eui-form>
|
||||
<eui-spacer
|
||||
size="l"
|
||||
|
@ -193,16 +222,39 @@ exports[`FieldEditor should render edit scripted field correctly 1`] = `
|
|||
size="m"
|
||||
/>
|
||||
<eui-form>
|
||||
<scripting-disabled-callOut
|
||||
isVisible={false}
|
||||
/>
|
||||
<scripting-warning-callOut
|
||||
isVisible={true}
|
||||
/>
|
||||
<scripting-help-flyout
|
||||
isVisible={false}
|
||||
onClose={[Function]}
|
||||
/>
|
||||
<React.Fragment>
|
||||
<scripting-disabled-callOut
|
||||
isVisible={false}
|
||||
/>
|
||||
<scripting-warning-callOut
|
||||
isVisible={true}
|
||||
/>
|
||||
<ScriptingHelpFlyout
|
||||
executeScript={[Function]}
|
||||
indexPattern={
|
||||
Object {
|
||||
"fields": Array [
|
||||
Object {
|
||||
"name": "foobar",
|
||||
},
|
||||
Object {
|
||||
"format": Format {},
|
||||
"lang": "painless",
|
||||
"name": "test",
|
||||
"script": "doc.test.value",
|
||||
"scripted": true,
|
||||
"type": "number",
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
isVisible={false}
|
||||
lang="painless"
|
||||
name="test"
|
||||
onClose={[Function]}
|
||||
script="doc.test.value"
|
||||
/>
|
||||
</React.Fragment>
|
||||
<eui-form-row
|
||||
helpText={null}
|
||||
label="Language"
|
||||
|
@ -301,59 +353,81 @@ exports[`FieldEditor should render edit scripted field correctly 1`] = `
|
|||
onChange={[Function]}
|
||||
/>
|
||||
</eui-form-row>
|
||||
<eui-form-row
|
||||
error={null}
|
||||
helpText={
|
||||
<eui-link
|
||||
onClick={[Function]}
|
||||
>
|
||||
Scripting help
|
||||
</eui-link>
|
||||
}
|
||||
isInvalid={false}
|
||||
label="Script"
|
||||
>
|
||||
<eui-textArea
|
||||
data-test-subj="editorFieldScript"
|
||||
<React.Fragment>
|
||||
<eui-form-row
|
||||
error={null}
|
||||
isInvalid={false}
|
||||
onChange={[Function]}
|
||||
value="doc.test.value"
|
||||
/>
|
||||
label="Script"
|
||||
>
|
||||
<eui-textArea
|
||||
data-test-subj="editorFieldScript"
|
||||
isInvalid={false}
|
||||
onChange={[Function]}
|
||||
value="doc.test.value"
|
||||
/>
|
||||
</eui-form-row>
|
||||
<eui-form-row>
|
||||
<React.Fragment>
|
||||
<eui-text>
|
||||
Access fields with
|
||||
<code>
|
||||
doc['some_field'].value
|
||||
</code>
|
||||
.
|
||||
</eui-text>
|
||||
<br />
|
||||
<eui-link
|
||||
data-test-subj="scriptedFieldsHelpLink"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Get help with the syntax and preview the results of your script.
|
||||
</eui-link>
|
||||
</React.Fragment>
|
||||
</eui-form-row>
|
||||
</React.Fragment>
|
||||
<eui-form-row>
|
||||
<eui-flex-group>
|
||||
<eui-flex-item
|
||||
grow={false}
|
||||
>
|
||||
<eui-button
|
||||
data-test-subj="fieldSaveButton"
|
||||
fill={true}
|
||||
isDisabled={false}
|
||||
isLoading={false}
|
||||
onClick={[Function]}
|
||||
>
|
||||
Save field
|
||||
</eui-button>
|
||||
</eui-flex-item>
|
||||
<eui-flex-item
|
||||
grow={false}
|
||||
>
|
||||
<eui-button-empty
|
||||
data-test-subj="fieldCancelButton"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Cancel
|
||||
</eui-button-empty>
|
||||
</eui-flex-item>
|
||||
<eui-flex-item>
|
||||
<eui-flex-group
|
||||
justifyContent="flexEnd"
|
||||
>
|
||||
<eui-flex-item
|
||||
grow={false}
|
||||
>
|
||||
<eui-button-empty
|
||||
color="danger"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Delete
|
||||
</eui-button-empty>
|
||||
</eui-flex-item>
|
||||
</eui-flex-group>
|
||||
</eui-flex-item>
|
||||
</eui-flex-group>
|
||||
</eui-form-row>
|
||||
<eui-flex-group>
|
||||
<eui-flex-item
|
||||
grow={false}
|
||||
>
|
||||
<eui-button
|
||||
data-test-subj="fieldSaveButton"
|
||||
fill={true}
|
||||
isDisabled={false}
|
||||
onClick={[Function]}
|
||||
>
|
||||
Save field
|
||||
</eui-button>
|
||||
</eui-flex-item>
|
||||
<eui-flex-item
|
||||
grow={false}
|
||||
>
|
||||
<eui-button-empty
|
||||
data-test-subj="fieldCancelButton"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Cancel
|
||||
</eui-button-empty>
|
||||
</eui-flex-item>
|
||||
<eui-flex-item
|
||||
grow={false}
|
||||
>
|
||||
<eui-button-empty
|
||||
color="danger"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Delete
|
||||
</eui-button-empty>
|
||||
</eui-flex-item>
|
||||
</eui-flex-group>
|
||||
</eui-form>
|
||||
<eui-spacer
|
||||
size="l"
|
||||
|
@ -372,16 +446,46 @@ exports[`FieldEditor should show conflict field warning 1`] = `
|
|||
size="m"
|
||||
/>
|
||||
<eui-form>
|
||||
<scripting-disabled-callOut
|
||||
isVisible={false}
|
||||
/>
|
||||
<scripting-warning-callOut
|
||||
isVisible={true}
|
||||
/>
|
||||
<scripting-help-flyout
|
||||
isVisible={false}
|
||||
onClose={[Function]}
|
||||
/>
|
||||
<React.Fragment>
|
||||
<scripting-disabled-callOut
|
||||
isVisible={false}
|
||||
/>
|
||||
<scripting-warning-callOut
|
||||
isVisible={true}
|
||||
/>
|
||||
<ScriptingHelpFlyout
|
||||
executeScript={[Function]}
|
||||
indexPattern={
|
||||
Object {
|
||||
"fields": Array [
|
||||
Object {
|
||||
"name": "foobar",
|
||||
},
|
||||
Object {
|
||||
"format": Format {},
|
||||
"lang": "painless",
|
||||
"name": "test",
|
||||
"script": "doc.test.value",
|
||||
"scripted": true,
|
||||
"type": "number",
|
||||
},
|
||||
Object {
|
||||
"format": Format {},
|
||||
"lang": "testlang",
|
||||
"name": "test",
|
||||
"script": "doc.test.value",
|
||||
"scripted": true,
|
||||
"type": "number",
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
isVisible={false}
|
||||
lang="painless"
|
||||
name="foobar"
|
||||
onClose={[Function]}
|
||||
/>
|
||||
</React.Fragment>
|
||||
<eui-form-row
|
||||
error={null}
|
||||
helpText={
|
||||
|
@ -511,48 +615,64 @@ exports[`FieldEditor should show conflict field warning 1`] = `
|
|||
onChange={[Function]}
|
||||
/>
|
||||
</eui-form-row>
|
||||
<eui-form-row
|
||||
error="Script is required"
|
||||
helpText={
|
||||
<eui-link
|
||||
onClick={[Function]}
|
||||
>
|
||||
Scripting help
|
||||
</eui-link>
|
||||
}
|
||||
isInvalid={true}
|
||||
label="Script"
|
||||
>
|
||||
<eui-textArea
|
||||
data-test-subj="editorFieldScript"
|
||||
<React.Fragment>
|
||||
<eui-form-row
|
||||
error="Script is required"
|
||||
isInvalid={true}
|
||||
onChange={[Function]}
|
||||
/>
|
||||
label="Script"
|
||||
>
|
||||
<eui-textArea
|
||||
data-test-subj="editorFieldScript"
|
||||
isInvalid={true}
|
||||
onChange={[Function]}
|
||||
/>
|
||||
</eui-form-row>
|
||||
<eui-form-row>
|
||||
<React.Fragment>
|
||||
<eui-text>
|
||||
Access fields with
|
||||
<code>
|
||||
doc['some_field'].value
|
||||
</code>
|
||||
.
|
||||
</eui-text>
|
||||
<br />
|
||||
<eui-link
|
||||
data-test-subj="scriptedFieldsHelpLink"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Get help with the syntax and preview the results of your script.
|
||||
</eui-link>
|
||||
</React.Fragment>
|
||||
</eui-form-row>
|
||||
</React.Fragment>
|
||||
<eui-form-row>
|
||||
<eui-flex-group>
|
||||
<eui-flex-item
|
||||
grow={false}
|
||||
>
|
||||
<eui-button
|
||||
data-test-subj="fieldSaveButton"
|
||||
fill={true}
|
||||
isDisabled={true}
|
||||
isLoading={false}
|
||||
onClick={[Function]}
|
||||
>
|
||||
Create field
|
||||
</eui-button>
|
||||
</eui-flex-item>
|
||||
<eui-flex-item
|
||||
grow={false}
|
||||
>
|
||||
<eui-button-empty
|
||||
data-test-subj="fieldCancelButton"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Cancel
|
||||
</eui-button-empty>
|
||||
</eui-flex-item>
|
||||
</eui-flex-group>
|
||||
</eui-form-row>
|
||||
<eui-flex-group>
|
||||
<eui-flex-item
|
||||
grow={false}
|
||||
>
|
||||
<eui-button
|
||||
data-test-subj="fieldSaveButton"
|
||||
fill={true}
|
||||
isDisabled={true}
|
||||
onClick={[Function]}
|
||||
>
|
||||
Create field
|
||||
</eui-button>
|
||||
</eui-flex-item>
|
||||
<eui-flex-item
|
||||
grow={false}
|
||||
>
|
||||
<eui-button-empty
|
||||
data-test-subj="fieldCancelButton"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Cancel
|
||||
</eui-button-empty>
|
||||
</eui-flex-item>
|
||||
</eui-flex-group>
|
||||
</eui-form>
|
||||
<eui-spacer
|
||||
size="l"
|
||||
|
@ -571,16 +691,47 @@ exports[`FieldEditor should show deprecated lang warning 1`] = `
|
|||
size="m"
|
||||
/>
|
||||
<eui-form>
|
||||
<scripting-disabled-callOut
|
||||
isVisible={false}
|
||||
/>
|
||||
<scripting-warning-callOut
|
||||
isVisible={true}
|
||||
/>
|
||||
<scripting-help-flyout
|
||||
isVisible={false}
|
||||
onClose={[Function]}
|
||||
/>
|
||||
<React.Fragment>
|
||||
<scripting-disabled-callOut
|
||||
isVisible={false}
|
||||
/>
|
||||
<scripting-warning-callOut
|
||||
isVisible={true}
|
||||
/>
|
||||
<ScriptingHelpFlyout
|
||||
executeScript={[Function]}
|
||||
indexPattern={
|
||||
Object {
|
||||
"fields": Array [
|
||||
Object {
|
||||
"name": "foobar",
|
||||
},
|
||||
Object {
|
||||
"format": Format {},
|
||||
"lang": "painless",
|
||||
"name": "test",
|
||||
"script": "doc.test.value",
|
||||
"scripted": true,
|
||||
"type": "number",
|
||||
},
|
||||
Object {
|
||||
"format": Format {},
|
||||
"lang": "testlang",
|
||||
"name": "test",
|
||||
"script": "doc.test.value",
|
||||
"scripted": true,
|
||||
"type": "number",
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
isVisible={false}
|
||||
lang="testlang"
|
||||
name="test"
|
||||
onClose={[Function]}
|
||||
script="doc.test.value"
|
||||
/>
|
||||
</React.Fragment>
|
||||
<eui-form-row
|
||||
helpText={
|
||||
<span>
|
||||
|
@ -735,59 +886,81 @@ exports[`FieldEditor should show deprecated lang warning 1`] = `
|
|||
onChange={[Function]}
|
||||
/>
|
||||
</eui-form-row>
|
||||
<eui-form-row
|
||||
error={null}
|
||||
helpText={
|
||||
<eui-link
|
||||
onClick={[Function]}
|
||||
>
|
||||
Scripting help
|
||||
</eui-link>
|
||||
}
|
||||
isInvalid={false}
|
||||
label="Script"
|
||||
>
|
||||
<eui-textArea
|
||||
data-test-subj="editorFieldScript"
|
||||
<React.Fragment>
|
||||
<eui-form-row
|
||||
error={null}
|
||||
isInvalid={false}
|
||||
onChange={[Function]}
|
||||
value="doc.test.value"
|
||||
/>
|
||||
label="Script"
|
||||
>
|
||||
<eui-textArea
|
||||
data-test-subj="editorFieldScript"
|
||||
isInvalid={false}
|
||||
onChange={[Function]}
|
||||
value="doc.test.value"
|
||||
/>
|
||||
</eui-form-row>
|
||||
<eui-form-row>
|
||||
<React.Fragment>
|
||||
<eui-text>
|
||||
Access fields with
|
||||
<code>
|
||||
doc['some_field'].value
|
||||
</code>
|
||||
.
|
||||
</eui-text>
|
||||
<br />
|
||||
<eui-link
|
||||
data-test-subj="scriptedFieldsHelpLink"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Get help with the syntax and preview the results of your script.
|
||||
</eui-link>
|
||||
</React.Fragment>
|
||||
</eui-form-row>
|
||||
</React.Fragment>
|
||||
<eui-form-row>
|
||||
<eui-flex-group>
|
||||
<eui-flex-item
|
||||
grow={false}
|
||||
>
|
||||
<eui-button
|
||||
data-test-subj="fieldSaveButton"
|
||||
fill={true}
|
||||
isDisabled={false}
|
||||
isLoading={false}
|
||||
onClick={[Function]}
|
||||
>
|
||||
Save field
|
||||
</eui-button>
|
||||
</eui-flex-item>
|
||||
<eui-flex-item
|
||||
grow={false}
|
||||
>
|
||||
<eui-button-empty
|
||||
data-test-subj="fieldCancelButton"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Cancel
|
||||
</eui-button-empty>
|
||||
</eui-flex-item>
|
||||
<eui-flex-item>
|
||||
<eui-flex-group
|
||||
justifyContent="flexEnd"
|
||||
>
|
||||
<eui-flex-item
|
||||
grow={false}
|
||||
>
|
||||
<eui-button-empty
|
||||
color="danger"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Delete
|
||||
</eui-button-empty>
|
||||
</eui-flex-item>
|
||||
</eui-flex-group>
|
||||
</eui-flex-item>
|
||||
</eui-flex-group>
|
||||
</eui-form-row>
|
||||
<eui-flex-group>
|
||||
<eui-flex-item
|
||||
grow={false}
|
||||
>
|
||||
<eui-button
|
||||
data-test-subj="fieldSaveButton"
|
||||
fill={true}
|
||||
isDisabled={false}
|
||||
onClick={[Function]}
|
||||
>
|
||||
Save field
|
||||
</eui-button>
|
||||
</eui-flex-item>
|
||||
<eui-flex-item
|
||||
grow={false}
|
||||
>
|
||||
<eui-button-empty
|
||||
data-test-subj="fieldCancelButton"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Cancel
|
||||
</eui-button-empty>
|
||||
</eui-flex-item>
|
||||
<eui-flex-item
|
||||
grow={false}
|
||||
>
|
||||
<eui-button-empty
|
||||
color="danger"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Delete
|
||||
</eui-button-empty>
|
||||
</eui-flex-item>
|
||||
</eui-flex-group>
|
||||
</eui-form>
|
||||
<eui-spacer
|
||||
size="l"
|
||||
|
|
|
@ -20,9 +20,26 @@
|
|||
import { PureComponent } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import {
|
||||
convertSampleInput
|
||||
} from '../../../../lib';
|
||||
export const convertSampleInput = (converter, inputs) => {
|
||||
let error = null;
|
||||
let samples = [];
|
||||
|
||||
try {
|
||||
samples = inputs.map(input => {
|
||||
return {
|
||||
input,
|
||||
output: converter(input),
|
||||
};
|
||||
});
|
||||
} catch(e) {
|
||||
error = `An error occurred while trying to use this format configuration: ${e.message}`;
|
||||
}
|
||||
|
||||
return {
|
||||
error,
|
||||
samples,
|
||||
};
|
||||
};
|
||||
|
||||
export class DefaultFormatEditor extends PureComponent {
|
||||
static propTypes = {
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import { DefaultFormatEditor } from './default';
|
||||
import { DefaultFormatEditor, convertSampleInput } from './default';
|
||||
|
||||
const fieldType = 'number';
|
||||
const format = {
|
||||
|
@ -31,6 +31,39 @@ const onChange = jest.fn();
|
|||
const onError = jest.fn();
|
||||
|
||||
describe('DefaultFormatEditor', () => {
|
||||
|
||||
describe('convertSampleInput', () => {
|
||||
const converter = (input) => {
|
||||
if(isNaN(input)) {
|
||||
throw {
|
||||
message: 'Input is not a number'
|
||||
};
|
||||
} else {
|
||||
return input * 2;
|
||||
}
|
||||
};
|
||||
|
||||
it('should convert a set of inputs', () => {
|
||||
const inputs = [1, 10, 15];
|
||||
const output = convertSampleInput(converter, inputs);
|
||||
|
||||
expect(output.error).toEqual(null);
|
||||
expect(JSON.stringify(output.samples)).toEqual(JSON.stringify([
|
||||
{ input: 1, output: 2 },
|
||||
{ input: 10, output: 20 },
|
||||
{ input: 15, output: 30 },
|
||||
]));
|
||||
});
|
||||
|
||||
it('should return error if converter throws one', () => {
|
||||
const inputs = [1, 10, 15, 'invalid'];
|
||||
const output = convertSampleInput(converter, inputs);
|
||||
|
||||
expect(output.error).toEqual('An error occurred while trying to use this format configuration: Input is not a number');
|
||||
expect(JSON.stringify(output.samples)).toEqual(JSON.stringify([]));
|
||||
});
|
||||
});
|
||||
|
||||
it('should render nothing', async () => {
|
||||
const component = shallow(
|
||||
<DefaultFormatEditor
|
||||
|
|
|
@ -1,134 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ScriptingHelpFlyout should render normally 1`] = `
|
||||
<EuiFlyout
|
||||
hideCloseButton={false}
|
||||
onClose={[Function]}
|
||||
ownFocus={false}
|
||||
size="s"
|
||||
>
|
||||
<EuiFlyoutBody>
|
||||
<EuiText
|
||||
grow={true}
|
||||
>
|
||||
<h3>
|
||||
Scripting help
|
||||
</h3>
|
||||
<p>
|
||||
By default, Kibana scripted fields use
|
||||
<EuiLink
|
||||
color="primary"
|
||||
href="(docLink for scriptedFields.painless)"
|
||||
target="_window"
|
||||
type="button"
|
||||
>
|
||||
Painless
|
||||
<EuiIcon
|
||||
size="m"
|
||||
type="link"
|
||||
/>
|
||||
</EuiLink>
|
||||
, a simple and secure scripting language designed specifically for use with Elasticsearch, to access values in the document use the following format:
|
||||
</p>
|
||||
<p>
|
||||
<EuiCode>
|
||||
doc['some_field'].value
|
||||
</EuiCode>
|
||||
</p>
|
||||
<p>
|
||||
Painless is powerful but easy to use. It provides access to many
|
||||
<EuiLink
|
||||
color="primary"
|
||||
href="(docLink for scriptedFields.painlessApi)"
|
||||
target="_window"
|
||||
type="button"
|
||||
>
|
||||
native Java APIs
|
||||
<EuiIcon
|
||||
size="m"
|
||||
type="link"
|
||||
/>
|
||||
</EuiLink>
|
||||
. Read up on its
|
||||
<EuiLink
|
||||
color="primary"
|
||||
href="(docLink for scriptedFields.painlessSyntax)"
|
||||
target="_window"
|
||||
type="button"
|
||||
>
|
||||
syntax
|
||||
<EuiIcon
|
||||
size="m"
|
||||
type="link"
|
||||
/>
|
||||
</EuiLink>
|
||||
and you'll be up to speed in no time!
|
||||
</p>
|
||||
<p>
|
||||
Kibana currently imposes one special limitation on the painless scripts you write. They cannot contain named functions.
|
||||
</p>
|
||||
<p>
|
||||
Coming from an older version of Kibana? The
|
||||
<EuiLink
|
||||
color="primary"
|
||||
href="(docLink for scriptedFields.luceneExpressions)"
|
||||
target="_window"
|
||||
type="button"
|
||||
>
|
||||
Lucene Expressions
|
||||
<EuiIcon
|
||||
size="m"
|
||||
type="link"
|
||||
/>
|
||||
</EuiLink>
|
||||
you know and love are still available. Lucene expressions are a lot like JavaScript, but limited to basic arithmetic, bitwise and comparison operations.
|
||||
</p>
|
||||
<p>
|
||||
There are a few limitations when using Lucene Expressions:
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
Only numeric, boolean, date, and geo_point fields may be accessed
|
||||
</li>
|
||||
<li>
|
||||
Stored fields are not available
|
||||
</li>
|
||||
<li>
|
||||
If a field is sparse (only some documents contain a value), documents missing the field will have a value of 0
|
||||
</li>
|
||||
</ul>
|
||||
<p>
|
||||
Here are all the operations available to lucene expressions:
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
Arithmetic operators: + - * / %
|
||||
</li>
|
||||
<li>
|
||||
Bitwise operators: | & ^ ~ << >> >>>
|
||||
</li>
|
||||
<li>
|
||||
Boolean operators (including the ternary operator): && || ! ?:
|
||||
</li>
|
||||
<li>
|
||||
Comparison operators: < <= == >= >
|
||||
</li>
|
||||
<li>
|
||||
Common mathematic functions: abs ceil exp floor ln log10 logn max min sqrt pow
|
||||
</li>
|
||||
<li>
|
||||
Trigonometric library functions: acosh acos asinh asin atanh atan atan2 cosh cos sinh sin tanh tan
|
||||
</li>
|
||||
<li>
|
||||
Distance functions: haversin
|
||||
</li>
|
||||
<li>
|
||||
Miscellaneous functions: min, max
|
||||
</li>
|
||||
</ul>
|
||||
</EuiText>
|
||||
</EuiFlyoutBody>
|
||||
</EuiFlyout>
|
||||
`;
|
||||
|
||||
exports[`ScriptingHelpFlyout should render nothing if not visible 1`] = `""`;
|
|
@ -1,113 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { getDocLink } from 'ui/documentation_links';
|
||||
|
||||
import {
|
||||
EuiCode,
|
||||
EuiFlyout,
|
||||
EuiFlyoutBody,
|
||||
EuiIcon,
|
||||
EuiLink,
|
||||
EuiText,
|
||||
} from '@elastic/eui';
|
||||
|
||||
export const ScriptingHelpFlyout = ({
|
||||
isVisible = false,
|
||||
onClose = () => {},
|
||||
}) => {
|
||||
return isVisible ? (
|
||||
<EuiFlyout onClose={onClose} size="s">
|
||||
<EuiFlyoutBody>
|
||||
<EuiText>
|
||||
<h3>Scripting help</h3>
|
||||
<p>
|
||||
By default, Kibana scripted fields use {(
|
||||
<EuiLink
|
||||
target="_window"
|
||||
href={getDocLink('scriptedFields.painless')}
|
||||
>
|
||||
Painless <EuiIcon type="link"/>
|
||||
</EuiLink>
|
||||
)}, a simple and secure scripting language designed specifically for use with Elasticsearch,
|
||||
to access values in the document use the following format:
|
||||
</p>
|
||||
<p>
|
||||
<EuiCode>doc['some_field'].value</EuiCode>
|
||||
</p>
|
||||
<p>
|
||||
Painless is powerful but easy to use. It provides access to many {(
|
||||
<EuiLink
|
||||
target="_window"
|
||||
href={getDocLink('scriptedFields.painlessApi')}
|
||||
>
|
||||
native Java APIs <EuiIcon type="link"/>
|
||||
</EuiLink>
|
||||
)}. Read up on its {(
|
||||
<EuiLink
|
||||
target="_window"
|
||||
href={getDocLink('scriptedFields.painlessSyntax')}
|
||||
>
|
||||
syntax <EuiIcon type="link"/>
|
||||
</EuiLink>
|
||||
)} and you'll be up to speed in no time!
|
||||
</p>
|
||||
<p>
|
||||
Kibana currently imposes one special limitation on the painless scripts you write. They cannot contain named functions.
|
||||
</p>
|
||||
<p>
|
||||
Coming from an older version of Kibana? The {(
|
||||
<EuiLink
|
||||
target="_window"
|
||||
href={getDocLink('scriptedFields.luceneExpressions')}
|
||||
>
|
||||
Lucene Expressions <EuiIcon type="link"/>
|
||||
</EuiLink>
|
||||
)} you know and love are still available. Lucene expressions are a lot like JavaScript,
|
||||
but limited to basic arithmetic, bitwise and comparison operations.
|
||||
</p>
|
||||
<p>
|
||||
There are a few limitations when using Lucene Expressions:
|
||||
</p>
|
||||
<ul>
|
||||
<li> Only numeric, boolean, date, and geo_point fields may be accessed</li>
|
||||
<li> Stored fields are not available</li>
|
||||
<li> If a field is sparse (only some documents contain a value), documents missing the field will have a value of 0</li>
|
||||
</ul>
|
||||
<p>
|
||||
Here are all the operations available to lucene expressions:
|
||||
</p>
|
||||
<ul>
|
||||
<li> Arithmetic operators: + - * / %</li>
|
||||
<li> Bitwise operators: | & ^ ~ << >> >>></li>
|
||||
<li> Boolean operators (including the ternary operator): && || ! ?:</li>
|
||||
<li> Comparison operators: < <= == >= ></li>
|
||||
<li> Common mathematic functions: abs ceil exp floor ln log10 logn max min sqrt pow</li>
|
||||
<li> Trigonometric library functions: acosh acos asinh asin atanh atan atan2 cosh cos sinh sin tanh tan</li>
|
||||
<li> Distance functions: haversin</li>
|
||||
<li> Miscellaneous functions: min, max</li>
|
||||
</ul>
|
||||
</EuiText>
|
||||
</EuiFlyoutBody>
|
||||
</EuiFlyout>
|
||||
) : null;
|
||||
};
|
||||
|
||||
ScriptingHelpFlyout.displayName = 'ScriptingHelpFlyout';
|
|
@ -19,4 +19,3 @@
|
|||
|
||||
export { ScriptingDisabledCallOut } from './disabled_call_out';
|
||||
export { ScriptingWarningCallOut } from './warning_call_out';
|
||||
export { ScriptingHelpFlyout } from './help_flyout';
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ScriptingHelpFlyout should render normally 1`] = `
|
||||
<EuiFlyout
|
||||
data-test-subj="scriptedFieldsHelpFlyout"
|
||||
hideCloseButton={false}
|
||||
onClose={[Function]}
|
||||
ownFocus={false}
|
||||
size="m"
|
||||
>
|
||||
<EuiFlyoutBody>
|
||||
<EuiTabbedContent
|
||||
initialSelectedTab={
|
||||
Object {
|
||||
"content": <Unknown />,
|
||||
"data-test-subj": "syntaxTab",
|
||||
"id": "syntax",
|
||||
"name": "Syntax",
|
||||
}
|
||||
}
|
||||
tabs={
|
||||
Array [
|
||||
Object {
|
||||
"content": <Unknown />,
|
||||
"data-test-subj": "syntaxTab",
|
||||
"id": "syntax",
|
||||
"name": "Syntax",
|
||||
},
|
||||
Object {
|
||||
"content": <TestScript
|
||||
executeScript={[Function]}
|
||||
indexPattern={Object {}}
|
||||
lang="painless"
|
||||
name="myScriptedField"
|
||||
script={undefined}
|
||||
/>,
|
||||
"data-test-subj": "testTab",
|
||||
"id": "test",
|
||||
"name": "Preview results",
|
||||
},
|
||||
]
|
||||
}
|
||||
/>
|
||||
</EuiFlyoutBody>
|
||||
</EuiFlyout>
|
||||
`;
|
||||
|
||||
exports[`ScriptingHelpFlyout should render nothing if not visible 1`] = `""`;
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import {
|
||||
EuiFlyout,
|
||||
EuiFlyoutBody,
|
||||
EuiTabbedContent,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { ScriptingSyntax } from './scripting_syntax';
|
||||
import { TestScript } from './test_script';
|
||||
|
||||
export const ScriptingHelpFlyout = ({
|
||||
isVisible = false,
|
||||
onClose = () => {},
|
||||
indexPattern,
|
||||
lang,
|
||||
name,
|
||||
script,
|
||||
executeScript,
|
||||
}) => {
|
||||
const tabs = [{
|
||||
id: 'syntax',
|
||||
name: 'Syntax',
|
||||
['data-test-subj']: 'syntaxTab',
|
||||
content: <ScriptingSyntax />,
|
||||
}, {
|
||||
id: 'test',
|
||||
name: 'Preview results',
|
||||
['data-test-subj']: 'testTab',
|
||||
content: (
|
||||
<TestScript
|
||||
indexPattern={indexPattern}
|
||||
lang={lang}
|
||||
name={name}
|
||||
script={script}
|
||||
executeScript={executeScript}
|
||||
/>
|
||||
),
|
||||
}];
|
||||
|
||||
return isVisible ? (
|
||||
<EuiFlyout onClose={onClose} data-test-subj="scriptedFieldsHelpFlyout">
|
||||
<EuiFlyoutBody>
|
||||
<EuiTabbedContent
|
||||
tabs={tabs}
|
||||
initialSelectedTab={tabs[0]}
|
||||
/>
|
||||
</EuiFlyoutBody>
|
||||
</EuiFlyout>
|
||||
) : null;
|
||||
};
|
||||
|
||||
ScriptingHelpFlyout.displayName = 'ScriptingHelpFlyout';
|
||||
|
||||
ScriptingHelpFlyout.propTypes = {
|
||||
indexPattern: PropTypes.object.isRequired,
|
||||
lang: PropTypes.string.isRequired,
|
||||
name: PropTypes.string,
|
||||
script: PropTypes.string,
|
||||
executeScript: PropTypes.func.isRequired,
|
||||
};
|
|
@ -26,11 +26,16 @@ jest.mock('ui/documentation_links', () => ({
|
|||
getDocLink: (doc) => `(docLink for ${doc})`,
|
||||
}));
|
||||
|
||||
const indexPatternMock = {};
|
||||
|
||||
describe('ScriptingHelpFlyout', () => {
|
||||
it('should render normally', async () => {
|
||||
const component = shallow(
|
||||
<ScriptingHelpFlyout
|
||||
isVisible={true}
|
||||
indexPattern={indexPatternMock}
|
||||
lang="painless"
|
||||
executeScript={() => {}}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -39,7 +44,11 @@ describe('ScriptingHelpFlyout', () => {
|
|||
|
||||
it('should render nothing if not visible', async () => {
|
||||
const component = shallow(
|
||||
<ScriptingHelpFlyout />
|
||||
<ScriptingHelpFlyout
|
||||
indexPattern={indexPatternMock}
|
||||
lang="painless"
|
||||
executeScript={() => {}}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(component).toMatchSnapshot();
|
|
@ -17,23 +17,4 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
export const convertSampleInput = (converter, inputs) => {
|
||||
let error = null;
|
||||
let samples = [];
|
||||
|
||||
try {
|
||||
samples = inputs.map(input => {
|
||||
return {
|
||||
input,
|
||||
output: converter(input),
|
||||
};
|
||||
});
|
||||
} catch(e) {
|
||||
error = `An error occurred while trying to use this format configuration: ${e.message}`;
|
||||
}
|
||||
|
||||
return {
|
||||
error,
|
||||
samples,
|
||||
};
|
||||
};
|
||||
export { ScriptingHelpFlyout } from './help_flyout';
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import React, { Fragment } from 'react';
|
||||
import { getDocLink } from 'ui/documentation_links';
|
||||
|
||||
import {
|
||||
EuiCode,
|
||||
EuiIcon,
|
||||
EuiLink,
|
||||
EuiText,
|
||||
EuiSpacer,
|
||||
} from '@elastic/eui';
|
||||
|
||||
export const ScriptingSyntax = () => (
|
||||
<Fragment>
|
||||
<EuiSpacer />
|
||||
<EuiText>
|
||||
<h3>Syntax</h3>
|
||||
<p>
|
||||
By default, Kibana scripted fields use {(
|
||||
<EuiLink
|
||||
target="_window"
|
||||
href={getDocLink('scriptedFields.painless')}
|
||||
>
|
||||
Painless <EuiIcon type="link"/>
|
||||
</EuiLink>
|
||||
)}, a simple and secure scripting language designed specifically for use with Elasticsearch,
|
||||
to access values in the document use the following format:
|
||||
</p>
|
||||
<p>
|
||||
<EuiCode>doc['some_field'].value</EuiCode>
|
||||
</p>
|
||||
<p>
|
||||
Painless is powerful but easy to use. It provides access to many {(
|
||||
<EuiLink
|
||||
target="_window"
|
||||
href={getDocLink('scriptedFields.painlessApi')}
|
||||
>
|
||||
native Java APIs <EuiIcon type="link"/>
|
||||
</EuiLink>
|
||||
)}. Read up on its {(
|
||||
<EuiLink
|
||||
target="_window"
|
||||
href={getDocLink('scriptedFields.painlessSyntax')}
|
||||
>
|
||||
syntax <EuiIcon type="link"/>
|
||||
</EuiLink>
|
||||
)} and you'll be up to speed in no time!
|
||||
</p>
|
||||
<p>
|
||||
Kibana currently imposes one special limitation on the painless scripts you write. They cannot contain named functions.
|
||||
</p>
|
||||
<p>
|
||||
Coming from an older version of Kibana? The {(
|
||||
<EuiLink
|
||||
target="_window"
|
||||
href={getDocLink('scriptedFields.luceneExpressions')}
|
||||
>
|
||||
Lucene Expressions <EuiIcon type="link"/>
|
||||
</EuiLink>
|
||||
)} you know and love are still available. Lucene expressions are a lot like JavaScript,
|
||||
but limited to basic arithmetic, bitwise and comparison operations.
|
||||
</p>
|
||||
<p>
|
||||
There are a few limitations when using Lucene Expressions:
|
||||
</p>
|
||||
<ul>
|
||||
<li> Only numeric, boolean, date, and geo_point fields may be accessed</li>
|
||||
<li> Stored fields are not available</li>
|
||||
<li> If a field is sparse (only some documents contain a value), documents missing the field will have a value of 0</li>
|
||||
</ul>
|
||||
<p>
|
||||
Here are all the operations available to lucene expressions:
|
||||
</p>
|
||||
<ul>
|
||||
<li> Arithmetic operators: <code>+ - * / %</code></li>
|
||||
<li> Bitwise operators: <code>| & ^ ~ << >> >>></code></li>
|
||||
<li> Boolean operators (including the ternary operator): <code>&& || ! ?:</code></li>
|
||||
<li> Comparison operators: <code>< <= == >= ></code></li>
|
||||
<li> Common mathematic functions: <code>abs ceil exp floor ln log10 logn max min sqrt pow</code></li>
|
||||
<li> Trigonometric library functions: <code>acosh acos asinh asin atanh atan atan2 cosh cos sinh sin tanh tan</code></li>
|
||||
<li> Distance functions: <code>haversin</code></li>
|
||||
<li> Miscellaneous functions: <code>min, max</code></li>
|
||||
</ul>
|
||||
</EuiText>
|
||||
</Fragment>
|
||||
);
|
|
@ -0,0 +1,226 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import {
|
||||
EuiButton,
|
||||
EuiCodeBlock,
|
||||
EuiComboBox,
|
||||
EuiFormRow,
|
||||
EuiText,
|
||||
EuiSpacer,
|
||||
EuiTitle,
|
||||
EuiCallOut,
|
||||
} from '@elastic/eui';
|
||||
|
||||
export class TestScript extends Component {
|
||||
state = {
|
||||
isLoading: false,
|
||||
additionalFields: [],
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (this.props.script) {
|
||||
this.previewScript();
|
||||
}
|
||||
}
|
||||
|
||||
previewScript = async () => {
|
||||
const {
|
||||
indexPattern,
|
||||
lang,
|
||||
name,
|
||||
script,
|
||||
executeScript,
|
||||
} = this.props;
|
||||
|
||||
if (!script || script.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
isLoading: true,
|
||||
});
|
||||
|
||||
const scriptResponse = await executeScript({
|
||||
name,
|
||||
lang,
|
||||
script,
|
||||
indexPatternTitle: indexPattern.title,
|
||||
additionalFields: this.state.additionalFields.map(option => {
|
||||
return option.value;
|
||||
})
|
||||
});
|
||||
|
||||
if (scriptResponse.status !== 200) {
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
previewData: scriptResponse
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
previewData: scriptResponse.hits.hits.map(hit => ({
|
||||
_id: hit._id,
|
||||
...hit._source,
|
||||
...hit.fields,
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
onAdditionalFieldsChange = (selectedOptions) => {
|
||||
this.setState({
|
||||
additionalFields: selectedOptions
|
||||
});
|
||||
}
|
||||
|
||||
renderPreview() {
|
||||
const { previewData } = this.state;
|
||||
|
||||
if (!previewData) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (previewData.error) {
|
||||
return (
|
||||
<EuiCallOut
|
||||
title="There's an error in your script"
|
||||
color="danger"
|
||||
iconType="cross"
|
||||
>
|
||||
<EuiCodeBlock
|
||||
language="json"
|
||||
className="scriptPreviewCodeBlock"
|
||||
data-test-subj="scriptedFieldPreview"
|
||||
>
|
||||
{JSON.stringify(previewData.error, null, ' ')}
|
||||
</EuiCodeBlock>
|
||||
</EuiCallOut>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<EuiTitle size="xs"><p>First 10 results</p></EuiTitle>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiCodeBlock
|
||||
language="json"
|
||||
className="scriptPreviewCodeBlock"
|
||||
data-test-subj="scriptedFieldPreview"
|
||||
>
|
||||
{JSON.stringify(previewData, null, ' ')}
|
||||
</EuiCodeBlock>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
renderToolbar() {
|
||||
const fieldsByTypeMap = new Map();
|
||||
const fields = [];
|
||||
|
||||
this.props.indexPattern.fields
|
||||
.filter(field => {
|
||||
return !field.name.startsWith('_');
|
||||
})
|
||||
.forEach(field => {
|
||||
if (fieldsByTypeMap.has(field.type)) {
|
||||
const fieldsList = fieldsByTypeMap.get(field.type);
|
||||
fieldsList.push(field.name);
|
||||
fieldsByTypeMap.set(field.type, fieldsList);
|
||||
} else {
|
||||
fieldsByTypeMap.set(field.type, [field.name]);
|
||||
}
|
||||
});
|
||||
|
||||
fieldsByTypeMap.forEach((fieldsList, fieldType) => {
|
||||
fields.push({
|
||||
label: fieldType,
|
||||
options: fieldsList.sort().map(fieldName => {
|
||||
return { value: fieldName, label: fieldName };
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
fields.sort((a, b) => {
|
||||
if (a.label < b.label) return -1;
|
||||
if (a.label > b.label) return 1;
|
||||
return 0;
|
||||
});
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<EuiFormRow
|
||||
label="Additional fields"
|
||||
>
|
||||
<EuiComboBox
|
||||
placeholder="Select..."
|
||||
options={fields}
|
||||
selectedOptions={this.state.additionalFields}
|
||||
onChange={this.onAdditionalFieldsChange}
|
||||
data-test-subj="additionalFieldsSelect"
|
||||
/>
|
||||
</EuiFormRow>
|
||||
|
||||
<EuiButton
|
||||
onClick={this.previewScript}
|
||||
disabled={this.props.script ? false : true}
|
||||
isLoading={this.state.isLoading}
|
||||
data-test-subj="runScriptButton"
|
||||
>
|
||||
Run script
|
||||
</EuiButton>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Fragment>
|
||||
<EuiSpacer />
|
||||
<EuiText>
|
||||
<h3>Preview results</h3>
|
||||
<p>
|
||||
Run your script to preview the first 10 results. You can also select some
|
||||
additional fields to include in your results to gain more context.
|
||||
</p>
|
||||
</EuiText>
|
||||
<EuiSpacer />
|
||||
{this.renderToolbar()}
|
||||
<EuiSpacer />
|
||||
{this.renderPreview()}
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
TestScript.propTypes = {
|
||||
indexPattern: PropTypes.object.isRequired,
|
||||
lang: PropTypes.string.isRequired,
|
||||
name: PropTypes.string,
|
||||
script: PropTypes.string,
|
||||
executeScript: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
TestScript.defaultProps = {
|
||||
name: 'myScriptedField',
|
||||
};
|
|
@ -63,15 +63,18 @@ import {
|
|||
import {
|
||||
ScriptingDisabledCallOut,
|
||||
ScriptingWarningCallOut,
|
||||
ScriptingHelpFlyout,
|
||||
} from './components/scripting_call_outs';
|
||||
|
||||
import {
|
||||
ScriptingHelpFlyout,
|
||||
} from './components/scripting_help';
|
||||
|
||||
import {
|
||||
FieldFormatEditor
|
||||
} from './components/field_format_editor';
|
||||
|
||||
import { FIELD_TYPES_BY_LANG, DEFAULT_FIELD_TYPES } from './constants';
|
||||
import { copyField, getDefaultFormat } from './lib';
|
||||
import { copyField, getDefaultFormat, executeScript, isScriptValid } from './lib';
|
||||
|
||||
export class FieldEditor extends PureComponent {
|
||||
static propTypes = {
|
||||
|
@ -109,6 +112,8 @@ export class FieldEditor extends PureComponent {
|
|||
showScriptingHelp: false,
|
||||
showDeleteModal: false,
|
||||
hasFormatError: false,
|
||||
hasScriptError: false,
|
||||
isSaving: false,
|
||||
};
|
||||
this.supportedLangs = getSupportedScriptingLanguages();
|
||||
this.deprecatedLangs = getDeprecatedScriptingLanguages();
|
||||
|
@ -339,24 +344,46 @@ export class FieldEditor extends PureComponent {
|
|||
);
|
||||
}
|
||||
|
||||
onScriptChange = (e) => {
|
||||
this.setState({
|
||||
hasScriptError: false
|
||||
});
|
||||
this.onFieldChange('script', e.target.value);
|
||||
}
|
||||
|
||||
renderScript() {
|
||||
const { field } = this.state;
|
||||
const isInvalid = !field.script || !field.script.trim();
|
||||
const { field, hasScriptError } = this.state;
|
||||
const isInvalid = !field.script || !field.script.trim() || hasScriptError;
|
||||
const errorMsg = hasScriptError
|
||||
? (<span data-test-subj="invalidScriptError">Script is invalid. View script preview for details</span>)
|
||||
: 'Script is required';
|
||||
|
||||
return field.scripted ? (
|
||||
<EuiFormRow
|
||||
label="Script"
|
||||
helpText={(<EuiLink onClick={this.showScriptingHelp}>Scripting help</EuiLink>)}
|
||||
isInvalid={isInvalid}
|
||||
error={isInvalid ? 'Script is required' : null}
|
||||
>
|
||||
<EuiTextArea
|
||||
value={field.script}
|
||||
data-test-subj="editorFieldScript"
|
||||
onChange={(e) => { this.onFieldChange('script', e.target.value); }}
|
||||
<Fragment>
|
||||
<EuiFormRow
|
||||
label="Script"
|
||||
isInvalid={isInvalid}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
error={isInvalid ? errorMsg : null}
|
||||
>
|
||||
<EuiTextArea
|
||||
value={field.script}
|
||||
data-test-subj="editorFieldScript"
|
||||
onChange={this.onScriptChange}
|
||||
isInvalid={isInvalid}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
|
||||
<EuiFormRow>
|
||||
<Fragment>
|
||||
<EuiText>Access fields with <code>{`doc['some_field'].value`}</code>.</EuiText>
|
||||
<br />
|
||||
<EuiLink onClick={this.showScriptingHelp} data-test-subj="scriptedFieldsHelpLink">
|
||||
Get help with the syntax and preview the results of your script.
|
||||
</EuiLink>
|
||||
</Fragment>
|
||||
</EuiFormRow>
|
||||
|
||||
</Fragment>
|
||||
) : null;
|
||||
}
|
||||
|
||||
|
@ -409,42 +436,73 @@ export class FieldEditor extends PureComponent {
|
|||
}
|
||||
|
||||
renderActions() {
|
||||
const { isCreating, field } = this.state;
|
||||
const { isCreating, field, isSaving } = this.state;
|
||||
const { redirectAway } = this.props.helpers;
|
||||
|
||||
return (
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButton
|
||||
fill
|
||||
onClick={this.saveField}
|
||||
isDisabled={this.isSavingDisabled()}
|
||||
data-test-subj="fieldSaveButton"
|
||||
>
|
||||
{isCreating ? 'Create field' : 'Save field'}
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonEmpty
|
||||
onClick={redirectAway}
|
||||
data-test-subj="fieldCancelButton"
|
||||
>
|
||||
Cancel
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
{
|
||||
!isCreating && field.scripted ? (
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonEmpty
|
||||
color="danger"
|
||||
onClick={this.showDeleteModal}
|
||||
>
|
||||
Delete
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
) : null
|
||||
}
|
||||
</EuiFlexGroup>
|
||||
<EuiFormRow>
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButton
|
||||
fill
|
||||
onClick={this.saveField}
|
||||
isDisabled={this.isSavingDisabled()}
|
||||
isLoading={isSaving}
|
||||
data-test-subj="fieldSaveButton"
|
||||
>
|
||||
{isCreating ? 'Create field' : 'Save field'}
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonEmpty
|
||||
onClick={redirectAway}
|
||||
data-test-subj="fieldCancelButton"
|
||||
>
|
||||
Cancel
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
{
|
||||
!isCreating && field.scripted ? (
|
||||
<EuiFlexItem>
|
||||
<EuiFlexGroup justifyContent="flexEnd">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonEmpty
|
||||
color="danger"
|
||||
onClick={this.showDeleteModal}
|
||||
>
|
||||
Delete
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
) : null
|
||||
}
|
||||
</EuiFlexGroup>
|
||||
</EuiFormRow>
|
||||
);
|
||||
}
|
||||
|
||||
renderScriptingPanels = () => {
|
||||
const { scriptingLangs, field, showScriptingHelp } = this.state;
|
||||
|
||||
if (!field.scripted) {
|
||||
return;
|
||||
}
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<ScriptingDisabledCallOut isVisible={!scriptingLangs.length} />
|
||||
<ScriptingWarningCallOut isVisible />
|
||||
<ScriptingHelpFlyout
|
||||
isVisible={showScriptingHelp}
|
||||
onClose={this.hideScriptingHelp}
|
||||
indexPattern={this.props.indexPattern}
|
||||
lang={field.lang}
|
||||
name={field.name}
|
||||
script={field.script}
|
||||
executeScript={executeScript}
|
||||
/>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -464,12 +522,33 @@ export class FieldEditor extends PureComponent {
|
|||
}
|
||||
}
|
||||
|
||||
saveField = () => {
|
||||
const { redirectAway } = this.props.helpers;
|
||||
saveField = async () => {
|
||||
const field = this.state.field.toActualField();
|
||||
const { indexPattern } = this.props;
|
||||
const { fieldFormatId } = this.state;
|
||||
|
||||
const field = this.state.field.toActualField();
|
||||
if (field.scripted) {
|
||||
this.setState({
|
||||
isSaving: true
|
||||
});
|
||||
|
||||
const isValid = await isScriptValid({
|
||||
name: field.name,
|
||||
lang: field.lang,
|
||||
script: field.script,
|
||||
indexPatternTitle: indexPattern.title
|
||||
});
|
||||
|
||||
if (!isValid) {
|
||||
this.setState({
|
||||
hasScriptError: true,
|
||||
isSaving: false
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const { redirectAway } = this.props.helpers;
|
||||
const index = indexPattern.fields.findIndex(f => f.name === field.name);
|
||||
|
||||
if (index > -1) {
|
||||
|
@ -492,10 +571,11 @@ export class FieldEditor extends PureComponent {
|
|||
}
|
||||
|
||||
isSavingDisabled() {
|
||||
const { field, hasFormatError } = this.state;
|
||||
const { field, hasFormatError, hasScriptError } = this.state;
|
||||
|
||||
if(
|
||||
hasFormatError
|
||||
|| hasScriptError
|
||||
|| !field.name
|
||||
|| !field.name.trim()
|
||||
|| (field.scripted && (!field.script || !field.script.trim()))
|
||||
|
@ -507,7 +587,7 @@ export class FieldEditor extends PureComponent {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { isReady, isCreating, scriptingLangs, field, showScriptingHelp } = this.state;
|
||||
const { isReady, isCreating, field } = this.state;
|
||||
|
||||
return isReady ? (
|
||||
<div>
|
||||
|
@ -516,12 +596,7 @@ export class FieldEditor extends PureComponent {
|
|||
</EuiText>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiForm>
|
||||
<ScriptingDisabledCallOut isVisible={field.scripted && !scriptingLangs.length} />
|
||||
<ScriptingWarningCallOut isVisible={field.scripted} />
|
||||
<ScriptingHelpFlyout
|
||||
isVisible={field.scripted && showScriptingHelp}
|
||||
onClose={this.hideScriptingHelp}
|
||||
/>
|
||||
{this.renderScriptingPanels()}
|
||||
{this.renderName()}
|
||||
{this.renderLanguage()}
|
||||
{this.renderType()}
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
jest.mock('ui/kfetch', () => ({}));
|
||||
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { convertSampleInput } from '../convert_sample_input';
|
||||
|
||||
const converter = (input) => {
|
||||
if(isNaN(input)) {
|
||||
throw {
|
||||
message: 'Input is not a number'
|
||||
};
|
||||
} else {
|
||||
return input * 2;
|
||||
}
|
||||
};
|
||||
|
||||
describe('convertSampleInput', () => {
|
||||
it('should convert a set of inputs', () => {
|
||||
const inputs = [1, 10, 15];
|
||||
const output = convertSampleInput(converter, inputs);
|
||||
|
||||
expect(output.error).toEqual(null);
|
||||
expect(JSON.stringify(output.samples)).toEqual(JSON.stringify([
|
||||
{ input: 1, output: 2 },
|
||||
{ input: 10, output: 20 },
|
||||
{ input: 15, output: 30 },
|
||||
]));
|
||||
});
|
||||
|
||||
it('should return error if converter throws one', () => {
|
||||
const inputs = [1, 10, 15, 'invalid'];
|
||||
const output = convertSampleInput(converter, inputs);
|
||||
|
||||
expect(output.error).toEqual('An error occurred while trying to use this format configuration: Input is not a number');
|
||||
expect(JSON.stringify(output.samples)).toEqual(JSON.stringify([]));
|
||||
});
|
||||
});
|
|
@ -19,4 +19,4 @@
|
|||
|
||||
export { copyField } from './copy_field';
|
||||
export { getDefaultFormat } from './get_default_format';
|
||||
export { convertSampleInput } from './convert_sample_input';
|
||||
export { executeScript, isScriptValid } from './validate_script';
|
||||
|
|
63
src/ui/public/field_editor/lib/validate_script.js
Normal file
63
src/ui/public/field_editor/lib/validate_script.js
Normal file
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { kfetch } from 'ui/kfetch';
|
||||
|
||||
export const executeScript = async ({ name, lang, script, indexPatternTitle, additionalFields = [] }) => {
|
||||
// Using _msearch because _search with index name in path dorks everything up
|
||||
const header = {
|
||||
index: indexPatternTitle,
|
||||
ignore_unavailable: true,
|
||||
timeout: 30000
|
||||
};
|
||||
|
||||
const search = {
|
||||
query: {
|
||||
match_all: {}
|
||||
},
|
||||
script_fields: {
|
||||
[name]: {
|
||||
script: {
|
||||
lang,
|
||||
source: script
|
||||
}
|
||||
}
|
||||
},
|
||||
size: 10,
|
||||
};
|
||||
|
||||
if (additionalFields.length > 0) {
|
||||
search._source = additionalFields;
|
||||
}
|
||||
|
||||
const body = `${JSON.stringify(header)}\n${JSON.stringify(search)}\n`;
|
||||
const esResp = await kfetch({ method: 'POST', pathname: '/elasticsearch/_msearch', body });
|
||||
// unwrap _msearch response
|
||||
return esResp.responses[0];
|
||||
};
|
||||
|
||||
export const isScriptValid = async ({ name, lang, script, indexPatternTitle }) => {
|
||||
const scriptResponse = await executeScript({ name, lang, script, indexPatternTitle });
|
||||
|
||||
if (scriptResponse.status !== 200) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
|
@ -37,6 +37,7 @@ export default function ({ getService, getPageObjects }) {
|
|||
const log = getService('log');
|
||||
const remote = getService('remote');
|
||||
const retry = getService('retry');
|
||||
const testSubjects = getService('testSubjects');
|
||||
const PageObjects = getPageObjects(['common', 'header', 'settings', 'visualize', 'discover']);
|
||||
|
||||
describe('scripted fields', () => {
|
||||
|
@ -57,6 +58,20 @@ export default function ({ getService, getPageObjects }) {
|
|||
await PageObjects.settings.removeIndexPattern();
|
||||
});
|
||||
|
||||
it('should not allow saving of invalid scripts', async function () {
|
||||
await PageObjects.settings.navigateTo();
|
||||
await PageObjects.settings.clickKibanaIndices();
|
||||
await PageObjects.settings.clickScriptedFieldsTab();
|
||||
await PageObjects.settings.clickAddScriptedField();
|
||||
await PageObjects.settings.setScriptedFieldName('doomedScriptedField');
|
||||
await PageObjects.settings.setScriptedFieldScript(`doc['iHaveNoClosingTick].value`);
|
||||
await PageObjects.settings.clickSaveScriptedField();
|
||||
await retry.try(async () => {
|
||||
const invalidScriptErrorExists = await testSubjects.exists('invalidScriptError');
|
||||
expect(invalidScriptErrorExists).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('creating and using Lucence expression scripted fields', function describeIndexTests() {
|
||||
const scriptedExpressionFieldName = 'ram_expr1';
|
||||
|
||||
|
|
66
test/functional/apps/management/_scripted_fields_preview.js
Normal file
66
test/functional/apps/management/_scripted_fields_preview.js
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import expect from 'expect.js';
|
||||
|
||||
export default function ({ getService, getPageObjects }) {
|
||||
const kibanaServer = getService('kibanaServer');
|
||||
const remote = getService('remote');
|
||||
const PageObjects = getPageObjects(['settings']);
|
||||
const SCRIPTED_FIELD_NAME = 'myScriptedField';
|
||||
|
||||
describe('scripted fields preview', () => {
|
||||
before(async function () {
|
||||
await remote.setWindowSize(1200, 800);
|
||||
// delete .kibana index and then wait for Kibana to re-create it
|
||||
await kibanaServer.uiSettings.replace({ 'dateFormat:tz': 'UTC' });
|
||||
await PageObjects.settings.navigateTo();
|
||||
await PageObjects.settings.clickKibanaIndices();
|
||||
await PageObjects.settings.createIndexPattern();
|
||||
await kibanaServer.uiSettings.update({ 'dateFormat:tz': 'UTC' });
|
||||
|
||||
await PageObjects.settings.navigateTo();
|
||||
await PageObjects.settings.clickKibanaIndices();
|
||||
await PageObjects.settings.clickScriptedFieldsTab();
|
||||
await PageObjects.settings.clickAddScriptedField();
|
||||
await PageObjects.settings.setScriptedFieldName(SCRIPTED_FIELD_NAME);
|
||||
});
|
||||
|
||||
after(async function afterAll() {
|
||||
await PageObjects.settings.navigateTo();
|
||||
await PageObjects.settings.clickKibanaIndices();
|
||||
await PageObjects.settings.removeIndexPattern();
|
||||
});
|
||||
|
||||
it('should display script error when script is invalid', async function () {
|
||||
const scriptResults = await PageObjects.settings.executeScriptedField(`doc['iHaveNoClosingTick].value`);
|
||||
expect(scriptResults.includes('search_phase_execution_exception')).to.be(true);
|
||||
});
|
||||
|
||||
it('should display script results when script is valid', async function () {
|
||||
const scriptResults = await PageObjects.settings.executeScriptedField(`doc['bytes'].value * 2`);
|
||||
expect(scriptResults.replace(/\s/g, '').includes('"myScriptedField":[6196')).to.be(true);
|
||||
});
|
||||
|
||||
it('should display additional fields', async function () {
|
||||
const scriptResults = await PageObjects.settings.executeScriptedField(`doc['bytes'].value * 2`, ['bytes']);
|
||||
expect(scriptResults.replace(/\s/g, '').includes('"bytes":3098')).to.be(true);
|
||||
});
|
||||
});
|
||||
}
|
|
@ -40,6 +40,7 @@ export default function ({ getService, loadTestFile }) {
|
|||
loadTestFile(require.resolve('./_index_pattern_popularity'));
|
||||
loadTestFile(require.resolve('./_kibana_settings'));
|
||||
loadTestFile(require.resolve('./_scripted_fields'));
|
||||
loadTestFile(require.resolve('./_scripted_fields_preview'));
|
||||
loadTestFile(require.resolve('./_index_pattern_filter'));
|
||||
loadTestFile(require.resolve('./_scripted_fields_filter'));
|
||||
loadTestFile(require.resolve('./_import_objects'));
|
||||
|
|
|
@ -25,8 +25,9 @@ export function SettingsPageProvider({ getService, getPageObjects }) {
|
|||
const config = getService('config');
|
||||
const remote = getService('remote');
|
||||
const find = getService('find');
|
||||
const flyout = getService('flyout');
|
||||
const testSubjects = getService('testSubjects');
|
||||
const PageObjects = getPageObjects(['header', 'common']);
|
||||
const PageObjects = getPageObjects(['header', 'common', 'visualize']);
|
||||
|
||||
const defaultFindTimeout = config.get('timeouts.find');
|
||||
|
||||
|
@ -503,6 +504,54 @@ export function SettingsPageProvider({ getService, getPageObjects }) {
|
|||
await field.type(script);
|
||||
}
|
||||
|
||||
async openScriptedFieldHelp(activeTab) {
|
||||
log.debug('open Scripted Fields help');
|
||||
let isOpen = await testSubjects.exists('scriptedFieldsHelpFlyout');
|
||||
if (!isOpen) {
|
||||
await retry.try(async () => {
|
||||
await testSubjects.click('scriptedFieldsHelpLink');
|
||||
isOpen = await testSubjects.exists('scriptedFieldsHelpFlyout');
|
||||
if (!isOpen) {
|
||||
throw new Error('Failed to open scripted fields help');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (activeTab) {
|
||||
await testSubjects.click(activeTab);
|
||||
}
|
||||
}
|
||||
|
||||
async closeScriptedFieldHelp() {
|
||||
log.debug('close Scripted Fields help');
|
||||
let isOpen = await testSubjects.exists('scriptedFieldsHelpFlyout');
|
||||
if (isOpen) {
|
||||
await retry.try(async () => {
|
||||
await flyout.close('scriptedFieldsHelpFlyout');
|
||||
isOpen = await testSubjects.exists('scriptedFieldsHelpFlyout');
|
||||
if (isOpen) {
|
||||
throw new Error('Failed to close scripted fields help');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async executeScriptedField(script, additionalField) {
|
||||
log.debug('execute Scripted Fields help');
|
||||
await this.closeScriptedFieldHelp(); // ensure script help is closed so script input is not blocked
|
||||
await this.setScriptedFieldScript(script);
|
||||
await this.openScriptedFieldHelp('testTab');
|
||||
if (additionalField) {
|
||||
await PageObjects.visualize.setComboBox('additionalFieldsSelect', additionalField);
|
||||
await testSubjects.click('runScriptButton');
|
||||
}
|
||||
let scriptResults;
|
||||
await retry.try(async () => {
|
||||
scriptResults = await testSubjects.getVisibleText('scriptedFieldPreview');
|
||||
});
|
||||
return scriptResults;
|
||||
}
|
||||
|
||||
async importFile(path, overwriteAll = true) {
|
||||
log.debug(`importFile(${path})`);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue