Skip to content

Commit 344df24

Browse files
committed
Clarify data and persistence flow. Fix floating point precision bug.
- Send strings to API and ES client instead of objects.
1 parent 07abc99 commit 344df24

10 files changed

Lines changed: 158 additions & 173 deletions

File tree

x-pack/plugins/painless_lab/public/application/common/types.ts

Lines changed: 6 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,15 @@
44
* you may not use this file except in compliance with the Elastic License.
55
*/
66

7-
export interface ContextSetup {
8-
params?: any;
9-
document: Record<string, unknown>;
10-
index: string;
11-
}
12-
137
// This should be an enumerated list
148
export type Context = string;
159

16-
export interface Script {
17-
source: string;
18-
params?: Record<string, unknown>;
19-
}
20-
21-
export interface Request {
22-
script: Script;
23-
context?: Context;
24-
context_setup?: ContextSetup;
10+
export interface RequestPayloadConfig {
11+
code: string;
12+
context: string;
13+
parameters: string;
14+
index: string;
15+
document: string;
2516
}
2617

2718
export interface Response {
@@ -47,15 +38,3 @@ export interface ExecutionError {
4738
position: ExecutionErrorPosition;
4839
script: string;
4940
}
50-
51-
export type JsonArray = JsonValue[];
52-
export type JsonValue = null | boolean | number | string | JsonObject | JsonArray;
53-
54-
export interface JsonObject {
55-
[key: string]: JsonValue;
56-
}
57-
58-
export type ContextChangeHandler = (change: {
59-
context?: Partial<Context>;
60-
contextSetup?: Partial<ContextSetup>;
61-
}) => void;

x-pack/plugins/painless_lab/public/application/components/editor.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,18 @@ import { CodeEditor } from '../../../../../../src/plugins/kibana_react/public';
88

99
interface Props {
1010
code: string;
11-
setCode: (code: string) => void;
11+
onChange: (code: string) => void;
1212
}
1313

14-
export function Editor({ code, setCode }: Props) {
14+
export function Editor({ code, onChange }: Props) {
1515
return (
1616
<CodeEditor
1717
languageId="painless"
1818
// 99% width allows the editor to resize horizontally. 100% prevents it from resizing.
1919
width="99%"
2020
height="100%"
2121
value={code}
22-
onChange={setCode}
22+
onChange={onChange}
2323
options={{
2424
fontSize: 12,
2525
minimap: {

x-pack/plugins/painless_lab/public/application/components/main.tsx

Lines changed: 48 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ import { HttpSetup } from 'kibana/public';
88
import React, { useState, useEffect } from 'react';
99
import { EuiFlexGroup, EuiFlexItem, EuiTitle } from '@elastic/eui';
1010
import { i18n } from '@kbn/i18n';
11-
import { buildRequestPayload, formatJson, getFromLocalStorage } from '../lib/helpers';
12-
import { ContextChangeHandler } from '../common/types';
11+
import { buildRequestPayload, formatJson } from '../lib/helpers';
12+
import { painlessContextOptions } from '../common/constants';
1313
import { OutputPane } from './output_pane';
1414
import { MainControls } from './main_controls';
1515
import { Editor } from './editor';
@@ -21,39 +21,50 @@ interface Props {
2121
http: HttpSetup;
2222
}
2323

24+
const PAINLESS_LAB_KEY = 'painlessLabState';
25+
2426
export function Main({ http }: Props) {
25-
const [code, setCode] = useState(getFromLocalStorage('painlessLabCode', exampleScript));
27+
const [state, setState] = useState({
28+
code: exampleScript,
29+
context: painlessContextOptions[0].value,
30+
parameters: '',
31+
index: '',
32+
document: '',
33+
...JSON.parse(localStorage.getItem(PAINLESS_LAB_KEY) || '{}'),
34+
});
35+
2636
const [isRequestFlyoutOpen, setRequestFlyoutOpen] = useState(false);
37+
const { inProgress, response, submit } = useSubmitCode(http);
2738

28-
const [context, setContext] = useState(
29-
getFromLocalStorage('painlessLabContext', 'painless_test_without_params')
30-
);
39+
// Live-update the output and persist state as the user changes it.
40+
const { code, context, parameters, index, document } = state;
41+
useEffect(() => {
42+
submit(state);
43+
localStorage.setItem(PAINLESS_LAB_KEY, JSON.stringify(state));
44+
}, [state, submit]);
3145

32-
const [contextSetup, setContextSetup] = useState(
33-
getFromLocalStorage('painlessLabContextSetup', {}, true)
34-
);
46+
const onCodeChange = (newCode: string) => {
47+
setState({ ...state, code: newCode });
48+
};
3549

36-
const { inProgress, response, submit } = useSubmitCode(http);
50+
const onContextChange = (newContext: string) => {
51+
setState({ ...state, context: newContext });
52+
};
3753

38-
// Live-update the output as the user changes the input code.
39-
useEffect(() => {
40-
submit(code, context, contextSetup);
41-
}, [submit, code, context, contextSetup]);
54+
const onParametersChange = (newParameters: string) => {
55+
setState({ ...state, parameters: newParameters });
56+
};
4257

43-
const toggleRequestFlyout = () => {
44-
setRequestFlyoutOpen(!isRequestFlyoutOpen);
58+
const onIndexChange = (newIndex: string) => {
59+
setState({ ...state, index: newIndex });
4560
};
4661

47-
const contextChangeHandler: ContextChangeHandler = ({
48-
context: nextContext,
49-
contextSetup: nextContextSetup,
50-
}) => {
51-
if (nextContext) {
52-
setContext(nextContext);
53-
}
54-
if (nextContextSetup) {
55-
setContextSetup(nextContextSetup);
56-
}
62+
const onDocumentChange = (newDocument: string) => {
63+
setState({ ...state, document: newDocument });
64+
};
65+
66+
const toggleRequestFlyout = () => {
67+
setRequestFlyoutOpen(!isRequestFlyoutOpen);
5768
};
5869

5970
return (
@@ -68,16 +79,21 @@ export function Main({ http }: Props) {
6879
</h1>
6980
</EuiTitle>
7081

71-
<Editor code={code} setCode={setCode} />
82+
<Editor code={code} onChange={onCodeChange} />
7283
</EuiFlexItem>
7384

7485
<EuiFlexItem>
7586
<OutputPane
87+
isLoading={inProgress}
7688
response={response}
7789
context={context}
78-
contextSetup={contextSetup}
79-
isLoading={inProgress}
80-
onContextChange={contextChangeHandler}
90+
parameters={parameters}
91+
index={index}
92+
document={document}
93+
onContextChange={onContextChange}
94+
onParametersChange={onParametersChange}
95+
onIndexChange={onIndexChange}
96+
onDocumentChange={onDocumentChange}
8197
/>
8298
</EuiFlexItem>
8399
</EuiFlexGroup>
@@ -86,13 +102,13 @@ export function Main({ http }: Props) {
86102
isLoading={inProgress}
87103
toggleRequestFlyout={toggleRequestFlyout}
88104
isRequestFlyoutOpen={isRequestFlyoutOpen}
89-
reset={() => setCode(exampleScript)}
105+
reset={() => onCodeChange(exampleScript)}
90106
/>
91107

92108
{isRequestFlyoutOpen && (
93109
<RequestFlyout
94110
onClose={() => setRequestFlyoutOpen(false)}
95-
requestBody={formatJson(buildRequestPayload(code, context, contextSetup))}
111+
requestBody={buildRequestPayload({ code, context, document, index, parameters })}
96112
response={response ? formatJson(response.result || response.error) : ''}
97113
/>
98114
)}

x-pack/plugins/painless_lab/public/application/components/output_pane/context_tab.tsx

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,24 @@ import { i18n } from '@kbn/i18n';
2121

2222
import { CodeEditor } from '../../../../../../../src/plugins/kibana_react/public';
2323
import { painlessContextOptions } from '../../common/constants';
24-
import { ContextChangeHandler, ContextSetup } from '../../common/types';
2524

2625
interface Props {
27-
context: string;
28-
contextSetup: ContextSetup;
29-
onContextChange: ContextChangeHandler;
26+
context: any;
27+
index: string;
28+
document: string;
29+
onContextChange: (change: any) => void;
30+
onIndexChange: (change: string) => void;
31+
onDocumentChange: (change: string) => void;
3032
}
3133

32-
export const ContextTab = ({ context, contextSetup, onContextChange }: Props) => (
34+
export const ContextTab = ({
35+
context,
36+
index,
37+
document,
38+
onContextChange,
39+
onIndexChange,
40+
onDocumentChange,
41+
}: Props) => (
3342
<>
3443
<EuiSpacer size="m" />
3544
<EuiFormRow
@@ -65,7 +74,7 @@ export const ContextTab = ({ context, contextSetup, onContextChange }: Props) =>
6574
<EuiSuperSelect
6675
options={painlessContextOptions}
6776
valueOfSelected={context}
68-
onChange={(value: any) => onContextChange({ context: value })}
77+
onChange={onContextChange}
6978
itemLayoutAlign="top"
7079
hasDividers
7180
fullWidth
@@ -88,15 +97,7 @@ export const ContextTab = ({ context, contextSetup, onContextChange }: Props) =>
8897
}
8998
fullWidth
9099
>
91-
<EuiFieldText
92-
fullWidth
93-
value={contextSetup.index || ''}
94-
onChange={e => {
95-
onContextChange({
96-
contextSetup: Object.assign({}, contextSetup, { index: e.target.value }),
97-
});
98-
}}
99-
/>
100+
<EuiFieldText fullWidth value={index || ''} onChange={e => onIndexChange(e.target.value)} />
100101
</EuiFormRow>
101102
)}
102103
{['filter', 'score'].indexOf(context) !== -1 && (
@@ -122,11 +123,8 @@ export const ContextTab = ({ context, contextSetup, onContextChange }: Props) =>
122123
<CodeEditor
123124
languageId="json"
124125
height={400}
125-
value={contextSetup.document || ''}
126-
onChange={(value: string) => {
127-
const newContextSetup = Object.assign({}, contextSetup, { document: value });
128-
onContextChange({ contextSetup: newContextSetup });
129-
}}
126+
value={document}
127+
onChange={onDocumentChange}
130128
options={{
131129
fontSize: 12,
132130
minimap: {

x-pack/plugins/painless_lab/public/application/components/output_pane/output_pane.tsx

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,36 @@ import {
1515
} from '@elastic/eui';
1616
import { i18n } from '@kbn/i18n';
1717

18-
import { Response, ContextSetup, Context, ContextChangeHandler } from '../../common/types';
18+
import { Response } from '../../common/types';
1919
import { OutputTab } from './output_tab';
2020
import { ParametersTab } from './parameters_tab';
2121
import { ContextTab } from './context_tab';
2222

2323
interface Props {
24-
context: Context;
25-
contextSetup: ContextSetup;
2624
isLoading: boolean;
27-
onContextChange: ContextChangeHandler;
2825
response?: Response;
26+
context: string;
27+
parameters: string;
28+
index: string;
29+
document: string;
30+
onContextChange: (change: string) => void;
31+
onParametersChange: (change: string) => void;
32+
onIndexChange: (change: string) => void;
33+
onDocumentChange: (change: string) => void;
2934
}
3035

31-
export function OutputPane({ response, context, contextSetup, onContextChange, isLoading }: Props) {
36+
export function OutputPane({
37+
isLoading,
38+
response,
39+
context,
40+
parameters,
41+
index,
42+
document,
43+
onContextChange,
44+
onParametersChange,
45+
onIndexChange,
46+
onDocumentChange,
47+
}: Props) {
3248
const outputTabLabel = (
3349
<EuiFlexGroup gutterSize="s" alignItems="center">
3450
<EuiFlexItem grow={false}>
@@ -67,7 +83,7 @@ export function OutputPane({ response, context, contextSetup, onContextChange, i
6783
defaultMessage: 'Parameters',
6884
}),
6985
content: (
70-
<ParametersTab contextSetup={contextSetup} onContextChange={onContextChange} />
86+
<ParametersTab parameters={parameters} onParametersChange={onParametersChange} />
7187
),
7288
},
7389
{
@@ -78,8 +94,11 @@ export function OutputPane({ response, context, contextSetup, onContextChange, i
7894
content: (
7995
<ContextTab
8096
context={context}
81-
contextSetup={contextSetup}
97+
index={index}
98+
document={document}
8299
onContextChange={onContextChange}
100+
onIndexChange={onIndexChange}
101+
onDocumentChange={onDocumentChange}
83102
/>
84103
),
85104
},

x-pack/plugins/painless_lab/public/application/components/output_pane/parameters_tab.tsx

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,13 @@ import {
1616
import { FormattedMessage } from '@kbn/i18n/react';
1717
import { i18n } from '@kbn/i18n';
1818
import { CodeEditor } from '../../../../../../../src/plugins/kibana_react/public';
19-
import { ContextChangeHandler, ContextSetup } from '../../common/types';
2019

2120
interface Props {
22-
contextSetup: ContextSetup;
23-
onContextChange: ContextChangeHandler;
21+
parameters: string;
22+
onParametersChange: (change: string) => void;
2423
}
2524

26-
export function ParametersTab({ contextSetup, onContextChange }: Props) {
25+
export function ParametersTab({ parameters, onParametersChange }: Props) {
2726
return (
2827
<>
2928
<EuiSpacer size="m" />
@@ -64,8 +63,8 @@ export function ParametersTab({ contextSetup, onContextChange }: Props) {
6463
<CodeEditor
6564
languageId="json"
6665
height={600}
67-
value={contextSetup.params}
68-
onChange={(value: string) => onContextChange({ contextSetup: { params: value } })}
66+
value={parameters}
67+
onChange={onParametersChange}
6968
options={{
7069
fontSize: 12,
7170
minimap: {

x-pack/plugins/painless_lab/public/application/hooks/use_submit_code.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@
77
import { useRef, useCallback, useState } from 'react';
88
import { HttpSetup } from 'kibana/public';
99
import { debounce } from 'lodash';
10-
import { Response } from '../common/types';
10+
11+
import { API_BASE_PATH } from '../../../common/constants';
12+
import { Response, RequestPayloadConfig } from '../common/types';
1113
import { buildRequestPayload } from '../lib/helpers';
12-
import { executeCode } from '../lib/execute_code';
1314

1415
const DEBOUNCE_MS = 800;
1516

@@ -20,18 +21,19 @@ export const useSubmitCode = (http: HttpSetup) => {
2021

2122
const submit = useCallback(
2223
debounce(
23-
async (code: string, context: string, contextSetup: Record<string, any>) => {
24+
async (config: RequestPayloadConfig) => {
2425
setInProgress(true);
2526

2627
// Prevent an older request that resolves after a more recent request from clobbering it.
2728
// We store the resulting ID in this closure for comparison when the request resolves.
2829
const requestId = ++currentRequestIdRef.current;
2930

3031
try {
31-
localStorage.setItem('painlessLabCode', code);
32-
localStorage.setItem('painlessLabContext', context);
33-
localStorage.setItem('painlessLabContextSetup', JSON.stringify(contextSetup));
34-
const result = await executeCode(http, buildRequestPayload(code, context, contextSetup));
32+
const result = await http.post(`${API_BASE_PATH}/execute`, {
33+
// Stringify the string, because http runs it through JSON.parse, and we want to actually
34+
// send a JSON string.
35+
body: JSON.stringify(buildRequestPayload(config)),
36+
});
3537

3638
if (currentRequestIdRef.current === requestId) {
3739
setResponse(result);

0 commit comments

Comments
 (0)