diff --git a/public/general_components/index.ts b/public/general_components/index.ts
index 60528d1e..ed0d4957 100644
--- a/public/general_components/index.ts
+++ b/public/general_components/index.ts
@@ -7,5 +7,6 @@ export { MultiSelectFilter } from './multi_select_filter';
export { ProcessorsTitle } from './processors_title';
export { ExperimentalBadge } from './experimental_badge';
export { QueryParamsList } from './query_params_list';
+export { JsonPathExamplesTable } from './jsonpath_examples_table';
export * from './results';
export * from './service_card';
diff --git a/public/general_components/jsonpath_examples_table.tsx b/public/general_components/jsonpath_examples_table.tsx
new file mode 100644
index 00000000..f336cb02
--- /dev/null
+++ b/public/general_components/jsonpath_examples_table.tsx
@@ -0,0 +1,62 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { EuiInMemoryTable, EuiCode, EuiText } from '@elastic/eui';
+
+interface JsonPathExamplesTableProps {}
+
+type JSONPathExample = {
+ expression: string;
+ meaning: string;
+ example: string;
+};
+
+const examples = [
+ {
+ expression: '$.data',
+ meaning: 'The entire input',
+ example: '$.data',
+ },
+] as JSONPathExample[];
+
+const columns = [
+ {
+ field: 'expression',
+ name: 'Expression',
+ width: '25%',
+ sortable: false,
+ render: (expression: string) => {expression},
+ },
+ {
+ field: 'meaning',
+ name: 'Meaning',
+ width: '50%',
+ sortable: false,
+ render: (meaning: string) => {meaning},
+ },
+ {
+ field: 'example',
+ name: 'Example',
+ width: '25%',
+ sortable: false,
+ render: (example: string) => {example},
+ },
+];
+
+/**
+ * A stateless component containing JSONPath examples in a table.
+ */
+export function JsonPathExamplesTable(props: JsonPathExamplesTableProps) {
+ return (
+
+ items={examples}
+ columns={columns}
+ pagination={false}
+ sorting={false}
+ hasActions={false}
+ />
+ );
+}
diff --git a/public/pages/workflow_detail/tools/query/query.tsx b/public/pages/workflow_detail/tools/query/query.tsx
index 155751d6..4d4be165 100644
--- a/public/pages/workflow_detail/tools/query/query.tsx
+++ b/public/pages/workflow_detail/tools/query/query.tsx
@@ -4,6 +4,7 @@
*/
import React, { useEffect, useState } from 'react';
+import { useSelector } from 'react-redux';
import { isEmpty } from 'lodash';
import { useFormikContext } from 'formik';
import {
@@ -13,7 +14,7 @@ import {
EuiFlexGroup,
EuiFlexItem,
EuiSmallButton,
- EuiSwitch,
+ EuiSmallButtonEmpty,
EuiText,
} from '@elastic/eui';
import {
@@ -24,7 +25,7 @@ import {
SearchResponse,
WorkflowFormValues,
} from '../../../../../common';
-import { searchIndex, useAppDispatch } from '../../../../store';
+import { AppState, searchIndex, useAppDispatch } from '../../../../store';
import {
containsEmptyValues,
containsSameValues,
@@ -57,12 +58,11 @@ export function Query(props: QueryProps) {
const dispatch = useAppDispatch();
const dataSourceId = getDataSourceId();
+ const { loading } = useSelector((state: AppState) => state.opensearch);
+
// Form state
const { values } = useFormikContext();
- // use custom query state
- const [useCustomQuery, setUseCustomQuery] = useState(false);
-
// query response state
const [queryResponse, setQueryResponse] = useState<
SearchResponse | undefined
@@ -158,11 +158,41 @@ export function Query(props: QueryProps) {
- Search
+
+
+ Search
+
+
+ {
+ setIncludePipeline(!includePipeline);
+ }}
+ />
+
+
- {
- setIncludePipeline(!includePipeline);
- }}
- />
+
+
+ Query
+
+ {props.selectedStep === CONFIG_STEP.SEARCH &&
+ !isEmpty(values?.search?.request) &&
+ values?.search?.request !== tempRequest && (
+
+ {
+ setTempRequest(values?.search?.request);
+ }}
+ >
+ Revert to query definition
+
+
+ )}
+
-
- setUseCustomQuery(!useCustomQuery)}
+
+ {
+ setTempRequest(input);
+ }}
+ onBlur={() => {
+ try {
+ setTempRequest(customStringify(JSON.parse(tempRequest)));
+ } catch (error) {}
+ }}
+ readOnly={false}
+ setOptions={{
+ fontSize: '14px',
+ useWorker: true,
+ highlightActiveLine: true,
+ highlightSelectedWord: true,
+ highlightGutterLine: true,
+ wrap: true,
+ }}
+ aria-label="Code Editor"
+ tabSize={2}
/>
- {useCustomQuery && (
-
- {
- setTempRequest(input);
- }}
- onBlur={() => {
- try {
- setTempRequest(
- customStringify(JSON.parse(tempRequest))
- );
- } catch (error) {}
- }}
- readOnly={false}
- setOptions={{
- fontSize: '14px',
- useWorker: true,
- highlightActiveLine: true,
- highlightSelectedWord: true,
- highlightGutterLine: true,
- wrap: true,
- }}
- aria-label="Code Editor"
- tabSize={2}
- />
-
- )}
{/**
* This may return nothing if the list of params are empty
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 3823bd29..ce18a570 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
@@ -4,6 +4,7 @@
*/
import React, { useEffect, useState } from 'react';
+import { useSelector } from 'react-redux';
import { Formik, getIn, useFormikContext } from 'formik';
import * as yup from 'yup';
import { isEmpty } from 'lodash';
@@ -42,7 +43,7 @@ import {
getPlaceholdersFromQuery,
injectParameters,
} from '../../../../utils';
-import { searchIndex, useAppDispatch } from '../../../../store';
+import { AppState, searchIndex, useAppDispatch } from '../../../../store';
import { QueryParamsList, Results } from '../../../../general_components';
interface EditQueryModalProps {
@@ -57,6 +58,7 @@ interface EditQueryModalProps {
export function EditQueryModal(props: EditQueryModalProps) {
const dispatch = useAppDispatch();
const dataSourceId = getDataSourceId();
+ const { loading } = useSelector((state: AppState) => state.opensearch);
// sub-form values/schema
const requestFormValues = {
@@ -257,6 +259,7 @@ export function EditQueryModal(props: EditQueryModalProps) {
{
dispatch(