diff --git a/common/constants.ts b/common/constants.ts index b8c51b85..76435d0b 100644 --- a/common/constants.ts +++ b/common/constants.ts @@ -185,6 +185,7 @@ export const NORMALIZATION_PROCESSOR_LINK = 'https://opensearch.org/docs/latest/search-plugins/search-pipelines/normalization-processor/'; export const GITHUB_FEEDBACK_LINK = 'https://github.com/opensearch-project/dashboards-flow-framework/issues/new/choose'; +export const JSONPATH_DOCS_LINK = 'https://www.npmjs.com/package/jsonpath'; /** * Text chunking algorithm constants diff --git a/public/general_components/jsonpath_examples_table.tsx b/public/general_components/jsonpath_examples_table.tsx index b05c9eb6..4b40c3b0 100644 --- a/public/general_components/jsonpath_examples_table.tsx +++ b/public/general_components/jsonpath_examples_table.tsx @@ -11,7 +11,10 @@ import { EuiText, EuiFlexGroup, EuiFlexItem, + EuiLink, + EuiSpacer, } from '@elastic/eui'; +import { JSONPATH_DOCS_LINK } from '../../common'; interface JsonPathExamplesTableProps { headerText?: string; @@ -25,9 +28,55 @@ type JSONPathExample = { const examples = [ { - expression: '$.data', - meaning: 'The entire input', - example: '$.data', + expression: '$', + meaning: 'The root object / element', + example: '$.my_field', + }, + { + expression: '.', + meaning: 'Child member operator', + example: 'my_field.my_sub_field', + }, + { + expression: '..', + meaning: + 'Recursive descendant operator, to specify an object field in an array of objects', + example: '$..my_field', + }, + { + expression: '*', + meaning: 'Wildcard matching all objects', + example: 'my_array.*', + }, + { + expression: '[]', + meaning: 'Subscript operator', + example: 'my_array[0]', + }, + { + expression: '[,]', + meaning: 'Union operator for alternate names or array indices as a set', + example: 'my_array[0,1]', + }, + { + expression: '[start:end:step]', + meaning: 'Array slice operator borrowed from ES4 / Python', + example: 'my_array[0:5]', + }, + { + expression: '@', + meaning: 'The current object / element in an array', + example: 'my_array[?(@.price<10)]', + }, + { + expression: '()', + meaning: 'Script expression via static evaluation', + example: 'my_array[?(@.price<10)]', + }, + { + expression: '?()', + meaning: 'Applies a filter (script) expression via static evaluation', + example: 'my_array[?(@.price<10)]', }, ] as JSONPathExample[]; @@ -61,7 +110,7 @@ const columns = [ */ export function JsonPathExamplesTable(props: JsonPathExamplesTableProps) { return ( - + {!isEmpty(props.headerText) && ( @@ -77,6 +126,12 @@ export function JsonPathExamplesTable(props: JsonPathExamplesTableProps) { hasActions={false} /> + + + + More examples & documentation + + ); diff --git a/public/pages/workflow_detail/workflow_inputs/processor_inputs/ml_processor_inputs/ml_processor_inputs.tsx b/public/pages/workflow_detail/workflow_inputs/processor_inputs/ml_processor_inputs/ml_processor_inputs.tsx index 995f39f6..c9286dcf 100644 --- a/public/pages/workflow_detail/workflow_inputs/processor_inputs/ml_processor_inputs/ml_processor_inputs.tsx +++ b/public/pages/workflow_detail/workflow_inputs/processor_inputs/ml_processor_inputs/ml_processor_inputs.tsx @@ -194,19 +194,11 @@ export function MLProcessorInputs(props: MLProcessorInputsProps) { @@ -222,13 +214,23 @@ export function MLProcessorInputs(props: MLProcessorInputsProps) { isDataFetchingAvailable={isInputPreviewAvailable} /> - + {`Outputs`} + + + (false); + // JSONPath details popover state + const [popoverOpen, setPopoverOpen] = useState(false); + // validation state utilizing the model interface, if applicable. undefined if // there is no model interface and/or no source input const [isValid, setIsValid] = useState(undefined); @@ -306,27 +312,39 @@ export function ConfigureExpressionModal(props: ConfigureExpressionModalProps) { - + - + {`Expression`} - + setPopoverOpen(false)} + button={ + setPopoverOpen(!popoverOpen)} + > + Learn more + + } + > + + @@ -339,18 +357,29 @@ export function ConfigureExpressionModal(props: ConfigureExpressionModalProps) { - + + + + + {props.context === + PROCESSOR_CONTEXT.SEARCH_RESPONSE && ( + + + {`Tip: to include data from the the original query request, prefix your expression with "${REQUEST_PREFIX}" - for example, "_request.query.match.my_field"`} + + + )} + {props.modelInputFieldName} - diff --git a/public/pages/workflow_detail/workflow_inputs/processor_inputs/ml_processor_inputs/modals/configure_multi_expression_modal.tsx b/public/pages/workflow_detail/workflow_inputs/processor_inputs/ml_processor_inputs/modals/configure_multi_expression_modal.tsx index a640a1ed..882c62fb 100644 --- a/public/pages/workflow_detail/workflow_inputs/processor_inputs/ml_processor_inputs/modals/configure_multi_expression_modal.tsx +++ b/public/pages/workflow_detail/workflow_inputs/processor_inputs/ml_processor_inputs/modals/configure_multi_expression_modal.tsx @@ -21,7 +21,7 @@ import { EuiSmallButtonEmpty, EuiSpacer, EuiSmallButtonIcon, - EuiIconTip, + EuiPopover, } from '@elastic/eui'; import { customStringify, @@ -59,7 +59,10 @@ import { useAppDispatch, } from '../../../../../../store'; import { getCore } from '../../../../../../services'; -import { QueryParamsList } from '../../../../../../general_components'; +import { + JsonPathExamplesTable, + QueryParamsList, +} from '../../../../../../general_components'; interface ConfigureMultiExpressionModalProps { uiConfig: WorkflowConfig; @@ -143,6 +146,9 @@ export function ConfigureMultiExpressionModal( // button updating state const [isUpdating, setIsUpdating] = useState(false); + // JSONPath details popover state + const [popoverOpen, setPopoverOpen] = useState(false); + // source input / transformed input state const [sourceInput, setSourceInput] = useState('{}'); const [transformedInput, setTransformedInput] = useState('{}'); @@ -278,18 +284,39 @@ export function ConfigureMultiExpressionModal( - + {`Expression`} - + setPopoverOpen(false)} + button={ + setPopoverOpen(!popoverOpen)} + > + Learn more + + } + > + + diff --git a/public/pages/workflow_detail/workflow_inputs/processor_inputs/ml_processor_inputs/modals/configure_template_modal.tsx b/public/pages/workflow_detail/workflow_inputs/processor_inputs/ml_processor_inputs/modals/configure_template_modal.tsx index dc0ab268..eb5612dc 100644 --- a/public/pages/workflow_detail/workflow_inputs/processor_inputs/ml_processor_inputs/modals/configure_template_modal.tsx +++ b/public/pages/workflow_detail/workflow_inputs/processor_inputs/ml_processor_inputs/modals/configure_template_modal.tsx @@ -65,7 +65,10 @@ import { useAppDispatch, } from '../../../../../../store'; import { getCore } from '../../../../../../services'; -import { QueryParamsList } from '../../../../../../general_components'; +import { + JsonPathExamplesTable, + QueryParamsList, +} from '../../../../../../general_components'; interface ConfigureTemplateModalProps { uiConfig: WorkflowConfig; @@ -166,6 +169,9 @@ export function ConfigureTemplateModal(props: ConfigureTemplateModalProps) { // popover states const [presetsPopoverOpen, setPresetsPopoverOpen] = useState(false); + const [jsonPathPopoverOpen, setJsonPathPopoverOpen] = useState( + false + ); // source input / transformed input state const [sourceInput, setSourceInput] = useState('{}'); @@ -448,9 +454,47 @@ export function ConfigureTemplateModal(props: ConfigureTemplateModalProps) { - - {`Expression`} - + + + + {`Expression`} + + + + + setJsonPathPopoverOpen(false) + } + button={ + + setJsonPathPopoverOpen( + !jsonPathPopoverOpen + ) + } + > + Learn more + + } + > + + + + diff --git a/public/utils/config_to_schema_utils.ts b/public/utils/config_to_schema_utils.ts index 3d3b3c98..8bcfb007 100644 --- a/public/utils/config_to_schema_utils.ts +++ b/public/utils/config_to_schema_utils.ts @@ -177,7 +177,7 @@ export function getFieldSchema( ) .test( 'jsonArray', - `Too large. Exceeds OpenSearch Dashboards limit of ${MAX_BYTES} bytes.`, + `The data size exceeds the limit of ${MAX_BYTES} bytes`, (value) => { try { // @ts-ignore