Skip to content

Commit 8afac97

Browse files
authored
Integrate query into form (not persisted in config) (opensearch-project#188)
Signed-off-by: Tyler Ohlsen <ohltyler@amazon.com>
1 parent 6efb453 commit 8afac97

File tree

9 files changed

+80
-100
lines changed

9 files changed

+80
-100
lines changed

common/interfaces.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ export type IngestConfig = {
5959
};
6060

6161
export type SearchConfig = {
62-
request: IConfig;
62+
request: {};
6363
enrichRequest: ProcessorsConfig;
6464
enrichResponse: ProcessorsConfig;
6565
};

public/pages/workflow_detail/resizable_workspace.tsx

+6-1
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ export function ResizableWorkspace(props: ResizableWorkspaceProps) {
5858
// ingest state
5959
const [ingestDocs, setIngestDocs] = useState<string>('');
6060

61+
// query state
62+
const [query, setQuery] = useState<string>('');
63+
6164
// Temp UI config state. For persisting changes to the UI config that may
6265
// not be saved in the backend (e.g., adding / removing an ingest processor)
6366
const [uiConfig, setUiConfig] = useState<WorkflowConfig | undefined>(
@@ -123,7 +126,7 @@ export function ResizableWorkspace(props: ResizableWorkspaceProps) {
123126
// Initialize the form state based on the current UI config
124127
useEffect(() => {
125128
if (uiConfig) {
126-
const initFormValues = uiConfigToFormik(uiConfig, ingestDocs);
129+
const initFormValues = uiConfigToFormik(uiConfig, ingestDocs, query);
127130
const initFormSchema = uiConfigToSchema(uiConfig);
128131
setFormValues(initFormValues);
129132
setFormSchema(initFormSchema);
@@ -187,6 +190,8 @@ export function ResizableWorkspace(props: ResizableWorkspaceProps) {
187190
setQueryResponse={setQueryResponse}
188191
ingestDocs={ingestDocs}
189192
setIngestDocs={setIngestDocs}
193+
query={query}
194+
setQuery={setQuery}
190195
/>
191196
</EuiResizablePanel>
192197
<EuiResizableButton />

public/pages/workflow_detail/workflow_inputs/search_inputs/configure_search_request.tsx

+27-61
Original file line numberDiff line numberDiff line change
@@ -3,38 +3,30 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
import React, { useEffect, useState } from 'react';
7-
import {
8-
EuiCodeEditor,
9-
EuiFieldText,
10-
EuiFlexGroup,
11-
EuiFlexItem,
12-
EuiFormRow,
13-
EuiTitle,
14-
} from '@elastic/eui';
15-
import { Field, FieldProps } from 'formik';
6+
import React, { useEffect } from 'react';
7+
import { EuiFlexGroup, EuiFlexItem, EuiTitle } from '@elastic/eui';
8+
import { useFormikContext } from 'formik';
9+
import { IConfigField, WorkspaceFormValues } from '../../../../../common';
10+
import { JsonField } from '../input_fields';
1611

1712
interface ConfigureSearchRequestProps {
18-
setQuery: (query: {}) => void;
13+
setQuery: (query: string) => void;
14+
onFormChange: () => void;
1915
}
2016

2117
/**
2218
* Input component for configuring a search request
2319
*/
2420
export function ConfigureSearchRequest(props: ConfigureSearchRequestProps) {
25-
const indexFieldPath = 'ingest.index.name';
26-
27-
// query state
28-
const [queryStr, setQueryStr] = useState<string>('{}');
21+
const { values } = useFormikContext<WorkspaceFormValues>();
2922

23+
// Hook to listen when the query form value changes.
24+
// Try to set the query request if possible
3025
useEffect(() => {
31-
try {
32-
const query = JSON.parse(queryStr);
33-
props.setQuery(query);
34-
} catch (e) {
35-
props.setQuery({});
26+
if (values?.search?.request) {
27+
props.setQuery(values.search.request);
3628
}
37-
}, [queryStr]);
29+
}, [values?.search?.request]);
3830

3931
return (
4032
<EuiFlexGroup direction="column">
@@ -43,46 +35,20 @@ export function ConfigureSearchRequest(props: ConfigureSearchRequestProps) {
4335
<h2>Configure query</h2>
4436
</EuiTitle>
4537
</EuiFlexItem>
46-
<EuiFlexItem>
47-
<EuiFlexGroup direction="column">
48-
<EuiFlexItem grow={false}>
49-
<Field name={indexFieldPath}>
50-
{({ field, form }: FieldProps) => {
51-
return (
52-
// TODO: make this dynamic depending on if ingest is defined or not.
53-
// 1/ (incomplete) if no ingest, make this a dropdown to select existing indices
54-
// 2/ (complete) if ingest, show the defined index from ingest config, make it readonly
55-
<EuiFormRow key={indexFieldPath} label={'Retrieval index'}>
56-
<EuiFieldText
57-
{...field}
58-
compressed={false}
59-
value={field.value}
60-
readOnly={true}
61-
/>
62-
</EuiFormRow>
63-
);
64-
}}
65-
</Field>
66-
</EuiFlexItem>
67-
<EuiFlexItem grow={false}>
68-
<EuiCodeEditor
69-
mode="json"
70-
theme="textmate"
71-
width="100%"
72-
height="25vh"
73-
value={queryStr}
74-
onChange={(input) => {
75-
setQueryStr(input);
76-
}}
77-
readOnly={false}
78-
setOptions={{
79-
fontSize: '14px',
80-
}}
81-
aria-label="Code Editor"
82-
tabSize={2}
83-
/>
84-
</EuiFlexItem>
85-
</EuiFlexGroup>
38+
<EuiFlexItem grow={false}>
39+
<JsonField
40+
// We want to integrate query into the form, but not persist in the config.
41+
// So, we create the ConfigField explicitly inline, instead of pulling
42+
// from the config.
43+
field={
44+
{
45+
label: 'Define query',
46+
} as IConfigField
47+
}
48+
fieldPath={'search.request'}
49+
onFormChange={props.onFormChange}
50+
editorHeight="25vh"
51+
/>
8652
</EuiFlexItem>
8753
</EuiFlexGroup>
8854
);

public/pages/workflow_detail/workflow_inputs/search_inputs/search_inputs.tsx

+5-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { WorkflowConfig } from '../../../../../common';
1313
interface SearchInputsProps {
1414
uiConfig: WorkflowConfig;
1515
setUiConfig: (uiConfig: WorkflowConfig) => void;
16-
setQuery: (query: {}) => void;
16+
setQuery: (query: string) => void;
1717
onFormChange: () => void;
1818
}
1919

@@ -24,7 +24,10 @@ export function SearchInputs(props: SearchInputsProps) {
2424
return (
2525
<EuiFlexGroup direction="column">
2626
<EuiFlexItem grow={false}>
27-
<ConfigureSearchRequest setQuery={props.setQuery} />
27+
<ConfigureSearchRequest
28+
setQuery={props.setQuery}
29+
onFormChange={props.onFormChange}
30+
/>
2831
</EuiFlexItem>
2932
<EuiFlexItem grow={false}>
3033
<EuiHorizontalRule margin="none" />

public/pages/workflow_detail/workflow_inputs/workflow_inputs.tsx

+12-6
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ interface WorkflowInputsProps {
5353
setQueryResponse: (queryResponse: string) => void;
5454
ingestDocs: string;
5555
setIngestDocs: (docs: string) => void;
56+
query: string;
57+
setQuery: (query: string) => void;
5658
}
5759

5860
export enum STEP {
@@ -77,9 +79,6 @@ export function WorkflowInputs(props: WorkflowInputsProps) {
7779
// ingest state
7880
const [ingestProvisioned, setIngestProvisioned] = useState<boolean>(false);
7981

80-
// query state
81-
const [query, setQuery] = useState<{}>({});
82-
8382
// maintain global states
8483
const onIngest = selectedStep === STEP.INGEST;
8584
const onIngestAndProvisioned = onIngest && ingestProvisioned;
@@ -145,6 +144,9 @@ export function WorkflowInputs(props: WorkflowInputsProps) {
145144
await validateForm()
146145
.then(async (validationResults: {}) => {
147146
if (Object.keys(validationResults).length > 0) {
147+
// TODO: may want to persist more fine-grained form validation (ingest vs. search)
148+
// For example, running an ingest should be possible, even with some
149+
// invalid query or search processor config. And vice versa.
148150
console.error('Form invalid');
149151
} else {
150152
const updatedConfig = formikToUiConfig(
@@ -206,11 +208,15 @@ export function WorkflowInputs(props: WorkflowInputsProps) {
206208
async function validateAndRunQuery(): Promise<boolean> {
207209
let success = false;
208210
try {
209-
if (!isEmpty(query)) {
211+
let queryObj = {};
212+
try {
213+
queryObj = JSON.parse(props.query);
214+
} catch (e) {}
215+
if (!isEmpty(queryObj)) {
210216
success = await validateAndUpdateWorkflow();
211217
if (success) {
212218
const indexName = values.ingest.index.name;
213-
dispatch(searchIndex({ index: indexName, body: query }))
219+
dispatch(searchIndex({ index: indexName, body: props.query }))
214220
.unwrap()
215221
.then(async (resp) => {
216222
const hits = resp.hits.hits;
@@ -290,7 +296,7 @@ export function WorkflowInputs(props: WorkflowInputsProps) {
290296
<SearchInputs
291297
uiConfig={props.uiConfig}
292298
setUiConfig={props.setUiConfig}
293-
setQuery={setQuery}
299+
setQuery={props.setQuery}
294300
onFormChange={props.onFormChange}
295301
/>
296302
)}

public/pages/workflows/new_workflow/utils.ts

+1-5
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,7 @@ function fetchEmptyMetadata(): UIState {
9191
},
9292
},
9393
search: {
94-
request: {
95-
id: 'request',
96-
name: 'Request',
97-
fields: [],
98-
},
94+
request: {},
9995
enrichRequest: {
10096
processors: [],
10197
},

public/utils/config_to_form_utils.ts

+6-5
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,12 @@ import {
2626
// and can be extremely large. so we pass that as a standalone field
2727
export function uiConfigToFormik(
2828
config: WorkflowConfig,
29-
ingestDocs: string
29+
ingestDocs: string,
30+
query: string
3031
): WorkflowFormValues {
3132
const formikValues = {} as WorkflowFormValues;
3233
formikValues['ingest'] = ingestConfigToFormik(config.ingest, ingestDocs);
33-
formikValues['search'] = searchConfigToFormik(config.search);
34+
formikValues['search'] = searchConfigToFormik(config.search, query);
3435
return formikValues;
3536
}
3637

@@ -81,12 +82,12 @@ function indexConfigToFormik(indexConfig: IndexConfig): FormikValues {
8182
}
8283

8384
function searchConfigToFormik(
84-
searchConfig: SearchConfig | undefined
85+
searchConfig: SearchConfig | undefined,
86+
query: string
8587
): FormikValues {
8688
let searchFormikValues = {} as FormikValues;
8789
if (searchConfig) {
88-
// TODO: implement for request
89-
searchFormikValues['request'] = {};
90+
searchFormikValues['request'] = query || getInitialValue('json');
9091
searchFormikValues['enrichRequest'] = processorsConfigToFormik(
9192
searchConfig.enrichRequest
9293
);

public/utils/config_to_schema_utils.ts

+22-15
Original file line numberDiff line numberDiff line change
@@ -39,19 +39,6 @@ function ingestConfigToSchema(
3939
return yup.object(ingestSchemaObj);
4040
}
4141

42-
function processorsConfigToSchema(processorsConfig: ProcessorsConfig): Schema {
43-
const processorsSchemaObj = {} as { [key: string]: Schema };
44-
processorsConfig.processors.forEach((processorConfig) => {
45-
const processorSchemaObj = {} as { [key: string]: Schema };
46-
processorConfig.fields.forEach((field) => {
47-
processorSchemaObj[field.id] = getFieldSchema(field.type);
48-
});
49-
processorsSchemaObj[processorConfig.id] = yup.object(processorSchemaObj);
50-
});
51-
52-
return yup.object(processorsSchemaObj);
53-
}
54-
5542
function indexConfigToSchema(indexConfig: IndexConfig): Schema {
5643
const indexSchemaObj = {} as { [key: string]: Schema };
5744
indexSchemaObj['name'] = getFieldSchema(indexConfig.name.type);
@@ -60,15 +47,35 @@ function indexConfigToSchema(indexConfig: IndexConfig): Schema {
6047
return yup.object(indexSchemaObj);
6148
}
6249

63-
// TODO: implement this
6450
function searchConfigToSchema(
6551
searchConfig: SearchConfig | undefined
6652
): ObjectSchema<any> {
6753
const searchSchemaObj = {} as { [key: string]: Schema };
68-
54+
if (searchConfig) {
55+
searchSchemaObj['request'] = getFieldSchema('json');
56+
searchSchemaObj['enrichRequest'] = processorsConfigToSchema(
57+
searchConfig.enrichRequest
58+
);
59+
searchSchemaObj['enrichResponse'] = processorsConfigToSchema(
60+
searchConfig.enrichResponse
61+
);
62+
}
6963
return yup.object(searchSchemaObj);
7064
}
7165

66+
function processorsConfigToSchema(processorsConfig: ProcessorsConfig): Schema {
67+
const processorsSchemaObj = {} as { [key: string]: Schema };
68+
processorsConfig.processors.forEach((processorConfig) => {
69+
const processorSchemaObj = {} as { [key: string]: Schema };
70+
processorConfig.fields.forEach((field) => {
71+
processorSchemaObj[field.id] = getFieldSchema(field.type);
72+
});
73+
processorsSchemaObj[processorConfig.id] = yup.object(processorSchemaObj);
74+
});
75+
76+
return yup.object(processorsSchemaObj);
77+
}
78+
7279
/*
7380
**************** Yup (validation) utils **********************
7481
*/

public/utils/config_to_workspace_utils.ts

-4
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,6 @@ import { generateId } from './utils';
3333
**************** Config -> workspace utils **********************
3434
*/
3535

36-
/*
37-
**************** ReactFlow workspace utils **********************
38-
*/
39-
4036
const PARENT_NODE_HEIGHT = 350;
4137
const NODE_HEIGHT_Y = 70;
4238
const NODE_WIDTH = 300; // based off of the value set in reactflow-styles.scss

0 commit comments

Comments
 (0)