diff --git a/public/general_components/processors_title.tsx b/public/general_components/processors_title.tsx
index fd718e5a..3e97ad61 100644
--- a/public/general_components/processors_title.tsx
+++ b/public/general_components/processors_title.tsx
@@ -9,6 +9,7 @@ import { EuiFlexItem, EuiText } from '@elastic/eui';
interface ProcessorsTitleProps {
title: string;
processorCount: number;
+ optional: boolean;
}
/**
@@ -24,11 +25,13 @@ export function ProcessorsTitle(props: ProcessorsTitleProps) {
<>
{`${props.title} (${props.processorCount}) -`}
+ >{`${props.title} (${props.processorCount})`}
-
- optional
-
+ {props.optional && (
+
+ - optional
+
+ )}
>
diff --git a/public/pages/workflow_detail/workflow_inputs/ingest_inputs/enrich_data.tsx b/public/pages/workflow_detail/workflow_inputs/ingest_inputs/enrich_data.tsx
index 4cb03de7..ae184a9e 100644
--- a/public/pages/workflow_detail/workflow_inputs/ingest_inputs/enrich_data.tsx
+++ b/public/pages/workflow_detail/workflow_inputs/ingest_inputs/enrich_data.tsx
@@ -23,6 +23,7 @@ export function EnrichData(props: EnrichDataProps) {
(false);
+ // query params state, if applicable. Users cannot run preview if there are query parameters
+ // and the user is configuring something in a search context (search request/response)
+ const [queryParams, setQueryParams] = useState([]);
+ useEffect(() => {
+ if (props.context !== PROCESSOR_CONTEXT.INGEST && query !== undefined) {
+ const placeholders = getPlaceholdersFromQuery(query);
+ if (
+ !containsSameValues(
+ placeholders,
+ queryParams.map((queryParam) => queryParam.name)
+ )
+ ) {
+ setQueryParams(
+ placeholders.map((placeholder) => ({
+ name: placeholder,
+ type: 'Text',
+ value: '',
+ }))
+ );
+ }
+ }
+ }, [query]);
+
// hook to re-generate the transform when any inputs to the transform are updated
useEffect(() => {
const tempExpressionAsInputMap = [
@@ -330,19 +359,21 @@ export function ConfigureExpressionModal(props: ConfigureExpressionModalProps) {
-
+
Preview
-
+
{
setIsFetching(true);
@@ -426,7 +457,9 @@ export function ConfigureExpressionModal(props: ConfigureExpressionModalProps) {
// this if check as an extra layer of checking, and if mechanism for gating
// this is changed in the future.
if (curSearchPipeline === undefined) {
- setSourceInput(values.search.request);
+ setSourceInput(
+ injectParameters(queryParams, query)
+ );
}
setIsFetching(false);
break;
@@ -448,7 +481,7 @@ export function ConfigureExpressionModal(props: ConfigureExpressionModalProps) {
index: values.search.index.name,
body: JSON.stringify({
...JSON.parse(
- values.search.request as string
+ injectParameters(queryParams, query)
),
search_pipeline:
curSearchPipeline || {},
@@ -490,6 +523,15 @@ export function ConfigureExpressionModal(props: ConfigureExpressionModalProps) {
+ {props.context !== PROCESSOR_CONTEXT.INGEST &&
+ !isEmpty(queryParams) && (
+
+
+
+ )}
Source data
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 c35c86df..a640a1ed 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
@@ -33,6 +33,7 @@ import {
MultiExpressionFormValues,
OutputMapEntry,
PROCESSOR_CONTEXT,
+ QueryParam,
SearchHit,
SearchPipelineConfig,
SimulateIngestPipelineResponse,
@@ -41,9 +42,13 @@ import {
WorkflowFormValues,
} from '../../../../../../../common';
import {
+ containsEmptyValues,
+ containsSameValues,
formikToPartialPipeline,
generateTransform,
getDataSourceId,
+ getPlaceholdersFromQuery,
+ injectParameters,
prepareDocsForSimulate,
unwrapTransformedDocs,
} from '../../../../../../utils';
@@ -54,6 +59,7 @@ import {
useAppDispatch,
} from '../../../../../../store';
import { getCore } from '../../../../../../services';
+import { QueryParamsList } from '../../../../../../general_components';
interface ConfigureMultiExpressionModalProps {
uiConfig: WorkflowConfig;
@@ -144,6 +150,29 @@ export function ConfigureMultiExpressionModal(
// fetching input data state
const [isFetching, setIsFetching] = useState(false);
+ // query params state, if applicable. Users cannot run preview if there are query parameters
+ // and the user is configuring something in a search context (search request/response)
+ const [queryParams, setQueryParams] = useState([]);
+ useEffect(() => {
+ if (props.context !== PROCESSOR_CONTEXT.INGEST && query !== undefined) {
+ const placeholders = getPlaceholdersFromQuery(query);
+ if (
+ !containsSameValues(
+ placeholders,
+ queryParams.map((queryParam) => queryParam.name)
+ )
+ ) {
+ setQueryParams(
+ placeholders.map((placeholder) => ({
+ name: placeholder,
+ type: 'Text',
+ value: '',
+ }))
+ );
+ }
+ }
+ }, [query]);
+
// hook to re-generate the transform when any inputs to the transform are updated
useEffect(() => {
const tempExpressionsAsOutputMap = tempExpressions.map(
@@ -356,19 +385,21 @@ export function ConfigureMultiExpressionModal(
-
+
Preview
-
+
{
setIsFetching(true);
@@ -482,7 +513,7 @@ export function ConfigureMultiExpressionModal(
index: values.search.index.name,
body: JSON.stringify({
...JSON.parse(
- values.search.request as string
+ injectParameters(queryParams, query)
),
search_pipeline:
curSearchPipeline || {},
@@ -522,6 +553,15 @@ export function ConfigureMultiExpressionModal(
+ {props.context !== PROCESSOR_CONTEXT.INGEST &&
+ !isEmpty(queryParams) && (
+
+
+
+ )}
Source data
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 ce3bb2cc..ffe7910c 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
@@ -43,13 +43,18 @@ import {
TRANSFORM_CONTEXT,
WorkflowConfig,
WorkflowFormValues,
+ QueryParam,
} from '../../../../../../../common';
import {
+ containsEmptyValues,
+ containsSameValues,
formikToPartialPipeline,
generateArrayTransform,
generateTransform,
getDataSourceId,
getInitialValue,
+ getPlaceholdersFromQuery,
+ injectParameters,
prepareDocsForSimulate,
unwrapTransformedDocs,
} from '../../../../../../utils';
@@ -60,6 +65,7 @@ import {
useAppDispatch,
} from '../../../../../../store';
import { getCore } from '../../../../../../services';
+import { QueryParamsList } from '../../../../../../general_components';
interface ConfigureTemplateModalProps {
uiConfig: WorkflowConfig;
@@ -168,6 +174,29 @@ export function ConfigureTemplateModal(props: ConfigureTemplateModalProps) {
// fetching input data state
const [isFetching, setIsFetching] = useState(false);
+ // query params state, if applicable. Users cannot run preview if there are query parameters
+ // and the user is configuring something in a search context (search request/response)
+ const [queryParams, setQueryParams] = useState([]);
+ useEffect(() => {
+ if (props.context !== PROCESSOR_CONTEXT.INGEST && query !== undefined) {
+ const placeholders = getPlaceholdersFromQuery(query);
+ if (
+ !containsSameValues(
+ placeholders,
+ queryParams.map((queryParam) => queryParam.name)
+ )
+ ) {
+ setQueryParams(
+ placeholders.map((placeholder) => ({
+ name: placeholder,
+ type: 'Text',
+ value: '',
+ }))
+ );
+ }
+ }
+ }, [query]);
+
// hook to re-generate the transform when any inputs to the transform are updated
useEffect(() => {
const nestedVarsAsInputMap = tempNestedVars?.map((expressionVar) => {
@@ -546,7 +575,9 @@ export function ConfigureTemplateModal(props: ConfigureTemplateModalProps) {
disabled={
onIngestAndNoDocs ||
onSearchAndNoQuery ||
- !props.isDataFetchingAvailable
+ !props.isDataFetchingAvailable ||
+ (props.context !== PROCESSOR_CONTEXT.INGEST &&
+ containsEmptyValues(queryParams))
}
onClick={async () => {
setIsFetching(true);
@@ -630,7 +661,9 @@ export function ConfigureTemplateModal(props: ConfigureTemplateModalProps) {
// this if check as an extra layer of checking, and if mechanism for gating
// this is changed in the future.
if (curSearchPipeline === undefined) {
- setSourceInput(values.search.request);
+ setSourceInput(
+ injectParameters(queryParams, query)
+ );
}
setIsFetching(false);
break;
@@ -652,7 +685,7 @@ export function ConfigureTemplateModal(props: ConfigureTemplateModalProps) {
index: values.search.index.name,
body: JSON.stringify({
...JSON.parse(
- values.search.request as string
+ injectParameters(queryParams, query)
),
search_pipeline:
curSearchPipeline || {},
@@ -694,6 +727,15 @@ export function ConfigureTemplateModal(props: ConfigureTemplateModalProps) {
+ {props.context !== PROCESSOR_CONTEXT.INGEST &&
+ !isEmpty(queryParams) && (
+
+
+
+ )}
Source data
diff --git a/public/pages/workflow_detail/workflow_inputs/processor_inputs/ml_processor_inputs/model_inputs.tsx b/public/pages/workflow_detail/workflow_inputs/processor_inputs/ml_processor_inputs/model_inputs.tsx
index 5fbdce24..6ec1da14 100644
--- a/public/pages/workflow_detail/workflow_inputs/processor_inputs/ml_processor_inputs/model_inputs.tsx
+++ b/public/pages/workflow_detail/workflow_inputs/processor_inputs/ml_processor_inputs/model_inputs.tsx
@@ -32,6 +32,7 @@ import {
EMPTY_INPUT_MAP_ENTRY,
WorkflowConfig,
getCharacterLimitedString,
+ ModelInputFormField,
} from '../../../../../../common';
import { TextField, SelectWithCustomOptions } from '../../input_fields';
import { AppState, getMappings, useAppDispatch } from '../../../../../store';
@@ -214,8 +215,31 @@ export function ModelInputs(props: ModelInputsProps) {
setFieldTouched(inputMapFieldPath, true);
}
- // Defining constants for the key/value text vars, typically dependent on the different processor contexts.
- const keyOptions = parseModelInputs(modelInterface);
+ // The options for keys can change. We update what options are available, based
+ // on if there is a model interface found, and additionally filter out any
+ // options that are already being used in the input map, to discourage duplicate keys.
+ const [keyOptions, setKeyOptions] = useState([]);
+ useEffect(() => {
+ setKeyOptions(parseModelInputs(modelInterface));
+ }, [modelInterface]);
+ useEffect(() => {
+ if (modelInterface !== undefined) {
+ const modelInputs = parseModelInputs(modelInterface);
+ if (getIn(values, inputMapFieldPath) !== undefined) {
+ const existingKeys = getIn(values, inputMapFieldPath).map(
+ (inputMapEntry: InputMapEntry) => inputMapEntry.key
+ ) as string[];
+ setKeyOptions(
+ modelInputs.filter(
+ (modelInput) => !existingKeys.includes(modelInput.label)
+ )
+ );
+ } else {
+ setKeyOptions(modelInputs);
+ }
+ }
+ }, [getIn(values, inputMapFieldPath), modelInterface]);
+
const valueOptions =
props.context === PROCESSOR_CONTEXT.INGEST
? docFields
diff --git a/public/pages/workflow_detail/workflow_inputs/processor_inputs/ml_processor_inputs/model_outputs.tsx b/public/pages/workflow_detail/workflow_inputs/processor_inputs/ml_processor_inputs/model_outputs.tsx
index 384f371f..0ca94d8d 100644
--- a/public/pages/workflow_detail/workflow_inputs/processor_inputs/ml_processor_inputs/model_outputs.tsx
+++ b/public/pages/workflow_detail/workflow_inputs/processor_inputs/ml_processor_inputs/model_outputs.tsx
@@ -21,6 +21,7 @@ import {
OutputMapFormValue,
EMPTY_OUTPUT_MAP_ENTRY,
ExpressionVar,
+ ModelOutputFormField,
} from '../../../../../../common';
import { SelectWithCustomOptions, TextField } from '../../input_fields';
@@ -136,9 +137,30 @@ export function ModelOutputs(props: ModelOutputsProps) {
setFieldTouched(outputMapFieldPath, true);
}
- const keyOptions = fullResponsePath
- ? undefined
- : parseModelOutputs(modelInterface, false);
+ // The options for keys can change. We update what options are available, based
+ // on if there is a model interface found, what full_response_path is, and additionally filter out any
+ // options that are already being used in the output map, to discourage duplicate keys.
+ const [keyOptions, setKeyOptions] = useState([]);
+ useEffect(() => {
+ setKeyOptions(parseModelOutputs(modelInterface));
+ }, [modelInterface]);
+ useEffect(() => {
+ if (modelInterface !== undefined && fullResponsePath === false) {
+ const modelOutputs = parseModelOutputs(modelInterface);
+ if (getIn(values, outputMapFieldPath) !== undefined) {
+ const existingKeys = getIn(values, outputMapFieldPath).map(
+ (outputMapEntry: OutputMapEntry) => outputMapEntry.key
+ ) as string[];
+ setKeyOptions(
+ modelOutputs.filter(
+ (modelOutput) => !existingKeys.includes(modelOutput.label)
+ )
+ );
+ } else {
+ setKeyOptions(modelOutputs);
+ }
+ }
+ }, [getIn(values, outputMapFieldPath), modelInterface, fullResponsePath]);
return (
diff --git a/public/pages/workflow_detail/workflow_inputs/search_inputs/enrich_search_request.tsx b/public/pages/workflow_detail/workflow_inputs/search_inputs/enrich_search_request.tsx
index 763eb6cf..d2fd3488 100644
--- a/public/pages/workflow_detail/workflow_inputs/search_inputs/enrich_search_request.tsx
+++ b/public/pages/workflow_detail/workflow_inputs/search_inputs/enrich_search_request.tsx
@@ -25,6 +25,7 @@ export function EnrichSearchRequest(props: EnrichSearchRequestProps) {
processorCount={
props.uiConfig.search.enrichRequest.processors?.length || 0
}
+ optional={false}
/>