From 9eeb5d92982913551486c4f1f6b3dda80a284259 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Wed, 30 Oct 2024 13:32:24 -0700 Subject: [PATCH] Add standalone form state for query editing modal (#450) (#455) (cherry picked from commit ba0dc6ab7d28a99fc6061d847d80f4bb12b18f9d) Signed-off-by: Tyler Ohlsen Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] --- common/interfaces.ts | 7 +- .../workflow_detail/workflow_detail.test.tsx | 6 +- .../ingest_inputs/source_data_modal.tsx | 3 +- .../search_inputs/edit_query_modal.tsx | 188 ++++++++++++------ 4 files changed, 136 insertions(+), 68 deletions(-) diff --git a/common/interfaces.ts b/common/interfaces.ts index 6f13aa71..c445a4f0 100644 --- a/common/interfaces.ts +++ b/common/interfaces.ts @@ -114,9 +114,14 @@ export type WorkflowSchema = ObjectSchema; export type IngestDocsFormValues = { docs: FormikValues; }; -export type IngestDocsSchemaObj = WorkflowSchemaObj; export type IngestDocsSchema = WorkflowSchema; +// Form / schema interfaces for the request query sub-form +export type RequestFormValues = { + request: ConfigFieldValue; +}; +export type RequestSchema = WorkflowSchema; + /** ********** WORKSPACE TYPES/INTERFACES ********** */ diff --git a/public/pages/workflow_detail/workflow_detail.test.tsx b/public/pages/workflow_detail/workflow_detail.test.tsx index dbeb7057..392ae963 100644 --- a/public/pages/workflow_detail/workflow_detail.test.tsx +++ b/public/pages/workflow_detail/workflow_detail.test.tsx @@ -229,9 +229,9 @@ describe('WorkflowDetail Page with skip ingestion option (Hybrid Search Workflow }); const searchQueryPresetButton = getByTestId('searchQueryPresetButton'); expect(searchQueryPresetButton).toBeInTheDocument(); - const searchQueryCloseButton = getByTestId('searchQueryCloseButton'); - expect(searchQueryCloseButton).toBeInTheDocument(); - userEvent.click(searchQueryCloseButton); + const updateSearchQueryButton = getByTestId('updateSearchQueryButton'); + expect(updateSearchQueryButton).toBeInTheDocument(); + userEvent.click(updateSearchQueryButton); // Add request processor const addRequestProcessorButton = await waitFor( diff --git a/public/pages/workflow_detail/workflow_inputs/ingest_inputs/source_data_modal.tsx b/public/pages/workflow_detail/workflow_inputs/ingest_inputs/source_data_modal.tsx index f871ce1b..ec700b7d 100644 --- a/public/pages/workflow_detail/workflow_inputs/ingest_inputs/source_data_modal.tsx +++ b/public/pages/workflow_detail/workflow_inputs/ingest_inputs/source_data_modal.tsx @@ -30,6 +30,7 @@ import { IConfigField, IndexMappings, IngestDocsFormValues, + IngestDocsSchema, isVectorSearchUseCase, SearchHit, SOURCE_OPTIONS, @@ -76,7 +77,7 @@ export function SourceDataModal(props: SourceDataProps) { docs: getFieldSchema({ type: 'jsonArray', } as IConfigField), - }); + }) as IngestDocsSchema; // persist standalone values. update / initialize when it is first opened const [tempDocs, setTempDocs] = useState('[]'); diff --git a/public/pages/workflow_detail/workflow_inputs/search_inputs/edit_query_modal.tsx b/public/pages/workflow_detail/workflow_inputs/search_inputs/edit_query_modal.tsx index 4549b715..eca28d3c 100644 --- a/public/pages/workflow_detail/workflow_inputs/search_inputs/edit_query_modal.tsx +++ b/public/pages/workflow_detail/workflow_inputs/search_inputs/edit_query_modal.tsx @@ -3,8 +3,10 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React, { useState } from 'react'; -import { useFormikContext } from 'formik'; +import React, { useEffect, useState } from 'react'; +import { Formik, getIn, useFormikContext } from 'formik'; +import * as yup from 'yup'; +import { isEmpty } from 'lodash'; import { EuiSmallButton, EuiContextMenu, @@ -18,10 +20,14 @@ import { } from '@elastic/eui'; import { JsonField } from '../input_fields'; import { + IConfigField, QUERY_PRESETS, QueryPreset, + RequestFormValues, + RequestSchema, WorkflowFormValues, } from '../../../../../common'; +import { getFieldSchema, getInitialValue } from '../../../../utils'; interface EditQueryModalProps { queryFieldPath: string; @@ -33,8 +39,22 @@ interface EditQueryModalProps { * a set of pre-defined queries targeted for different use cases. */ export function EditQueryModal(props: EditQueryModalProps) { + // sub-form values/schema + const requestFormValues = { + request: getInitialValue('json'), + } as RequestFormValues; + const requestFormSchema = yup.object({ + request: getFieldSchema({ + type: 'json', + } as IConfigField), + }) as RequestSchema; + + // persist standalone values. update / initialize when it is first opened + const [tempRequest, setTempRequest] = useState('{}'); + const [tempErrors, setTempErrors] = useState(false); + // Form state - const { setFieldValue, setFieldTouched } = useFormikContext< + const { values, setFieldValue, setFieldTouched } = useFormikContext< WorkflowFormValues >(); @@ -42,66 +62,108 @@ export function EditQueryModal(props: EditQueryModalProps) { const [popoverOpen, setPopoverOpen] = useState(false); return ( - props.setModalOpen(false)} - style={{ width: '70vw' }} - data-testid="editQueryModal" + {}} + validate={(values) => {}} > - - -

{`Edit query`}

-
-
- - setPopoverOpen(!popoverOpen)} - data-testid="searchQueryPresetButton" - > - Choose from a preset - - } - isOpen={popoverOpen} - closePopover={() => setPopoverOpen(false)} - anchorPosition="downLeft" - > - ({ - name: preset.name, - onClick: () => { - setFieldValue(props.queryFieldPath, preset.query); - setFieldTouched(props.queryFieldPath, true); - setPopoverOpen(false); - }, - })), - }, - ]} - /> - - - - - - props.setModalOpen(false)} - data-testid="searchQueryCloseButton" - fill={false} - color="primary" - > - Close - - -
+ {(formikProps) => { + // override to parent form value when changes detected + useEffect(() => { + formikProps.setFieldValue( + 'request', + getIn(values, props.queryFieldPath) + ); + }, [getIn(values, props.queryFieldPath)]); + + // update tempRequest when form changes are detected + useEffect(() => { + setTempRequest(getIn(formikProps.values, 'request')); + }, [getIn(formikProps.values, 'request')]); + + // update tempErrors if errors detected + useEffect(() => { + setTempErrors(!isEmpty(formikProps.errors)); + }, [formikProps.errors]); + + return ( + props.setModalOpen(false)} + style={{ width: '70vw' }} + data-testid="editQueryModal" + > + + +

{`Edit query`}

+
+
+ + setPopoverOpen(!popoverOpen)} + data-testid="searchQueryPresetButton" + > + Choose from a preset + + } + isOpen={popoverOpen} + closePopover={() => setPopoverOpen(false)} + anchorPosition="downLeft" + > + ({ + name: preset.name, + onClick: () => { + formikProps.setFieldValue('request', preset.query); + setPopoverOpen(false); + }, + })), + }, + ]} + /> + + + + + + props.setModalOpen(false)} + fill={false} + color="primary" + data-testid="cancelSearchQueryButton" + > + Cancel + + { + setFieldValue(props.queryFieldPath, tempRequest); + setFieldTouched(props.queryFieldPath, true); + props.setModalOpen(false); + }} + isDisabled={tempErrors} // blocking update until valid input is given + fill={true} + color="primary" + data-testid="updateSearchQueryButton" + > + Update + + +
+ ); + }} + ); }