diff --git a/public/pages/workflow_detail/workflow_inputs/input_fields/boolean_field.tsx b/public/pages/workflow_detail/workflow_inputs/input_fields/boolean_field.tsx
new file mode 100644
index 00000000..660f2b38
--- /dev/null
+++ b/public/pages/workflow_detail/workflow_inputs/input_fields/boolean_field.tsx
@@ -0,0 +1,41 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { Field, FieldProps } from 'formik';
+import { EuiRadioGroup, EuiRadioGroupOption } from '@elastic/eui';
+
+interface BooleanFieldProps {
+ fieldPath: string; // the full path in string-form to the field (e.g., 'ingest.enrich.processors.text_embedding_processor.inputField')
+ onFormChange: () => void;
+ enabledOption: EuiRadioGroupOption;
+ disabledOption: EuiRadioGroupOption;
+}
+
+/**
+ * An input field for a boolean value. Implemented as an EuiRadioGroup with 2 mutually exclusive options.
+ */
+export function BooleanField(props: BooleanFieldProps) {
+ return (
+
+ {({ field, form }: FieldProps) => {
+ return (
+ {
+ form.setFieldValue(field.name, !field.value);
+ props.onFormChange();
+ }}
+ />
+ );
+ }}
+
+ );
+}
diff --git a/public/pages/workflow_detail/workflow_inputs/input_fields/index.ts b/public/pages/workflow_detail/workflow_inputs/input_fields/index.ts
index b211fd3d..ca741ba6 100644
--- a/public/pages/workflow_detail/workflow_inputs/input_fields/index.ts
+++ b/public/pages/workflow_detail/workflow_inputs/input_fields/index.ts
@@ -8,3 +8,4 @@ export { JsonField } from './json_field';
export { SelectField } from './select_field';
export { ModelField } from './model_field';
export { MapField } from './map_field';
+export { BooleanField } from './boolean_field';
diff --git a/public/pages/workflow_detail/workflow_inputs/workflow_inputs.tsx b/public/pages/workflow_detail/workflow_inputs/workflow_inputs.tsx
index e849f783..a5f3d60d 100644
--- a/public/pages/workflow_detail/workflow_inputs/workflow_inputs.tsx
+++ b/public/pages/workflow_detail/workflow_inputs/workflow_inputs.tsx
@@ -14,7 +14,9 @@ import {
EuiHorizontalRule,
EuiLoadingSpinner,
EuiPanel,
+ EuiSpacer,
EuiStepsHorizontal,
+ EuiText,
EuiTitle,
} from '@elastic/eui';
import {
@@ -40,6 +42,7 @@ import {
configToTemplateFlows,
hasProvisionedIngestResources,
} from '../../../utils';
+import { BooleanField } from './input_fields';
// styling
import '../workspace/workspace-styles.scss';
@@ -57,11 +60,16 @@ interface WorkflowInputsProps {
setQuery: (query: string) => void;
}
-export enum STEP {
+enum STEP {
INGEST = 'Ingestion pipeline',
SEARCH = 'Search pipeline',
}
+enum INGEST_OPTION {
+ CREATE = 'create',
+ SKIP = 'skip',
+}
+
/**
* The workflow inputs component containing the multi-step flow to create ingest
* and search flows for a particular workflow.
@@ -81,8 +89,10 @@ export function WorkflowInputs(props: WorkflowInputsProps) {
// maintain global states
const onIngest = selectedStep === STEP.INGEST;
+ const ingestEnabled = values?.ingest?.enabled || false;
const onIngestAndProvisioned = onIngest && ingestProvisioned;
const onIngestAndUnprovisioned = onIngest && !ingestProvisioned;
+ const onIngestAndDisabled = onIngest && !ingestEnabled;
useEffect(() => {
setIngestProvisioned(hasProvisionedIngestResources(props.workflow));
@@ -265,42 +275,81 @@ export function WorkflowInputs(props: WorkflowInputsProps) {
onClick: () => {},
},
]}
- >
-
-
-
-
- {onIngestAndUnprovisioned
- ? 'Define ingest pipeline'
- : onIngestAndProvisioned
- ? 'Edit ingest pipeline'
- : 'Define search pipeline'}
-
-
-
-
- {onIngest ? (
-
- ) : (
-
+ />
+ {onIngest && (
+ <>
+
+
+
+ Create an ingest pipeline
+
+
+ Configure and ingest data into an index.
+
+
+ ),
+ }}
+ disabledOption={{
+ id: INGEST_OPTION.SKIP,
+ label: (
+
+
+ Skip ingestion pipeline
+
+
+ Use an existing index with data ingested.
+
+
+ ),
+ }}
+ />
+ >
)}
+ {!onIngestAndDisabled && (
+ <>
+
+
+
+ {onIngestAndUnprovisioned
+ ? 'Define ingest pipeline'
+ : onIngestAndProvisioned
+ ? 'Edit ingest pipeline'
+ : 'Define search pipeline'}
+
+
+
+
+ {onIngest ? (
+
+ ) : (
+
+ )}
+
+ >
+ )}
@@ -308,7 +357,16 @@ export function WorkflowInputs(props: WorkflowInputsProps) {
- {onIngestAndUnprovisioned ? (
+ {onIngest && !ingestEnabled ? (
+
+ setSelectedStep(STEP.SEARCH)}
+ >
+ {`Search pipeline >`}
+
+
+ ) : onIngestAndUnprovisioned ? (
<>
setSelectedStep(STEP.SEARCH)}
>
- {`Next >`}
+ {`Search pipeline >`}
>
diff --git a/public/utils/config_to_form_utils.ts b/public/utils/config_to_form_utils.ts
index c5dbc4da..96f7489f 100644
--- a/public/utils/config_to_form_utils.ts
+++ b/public/utils/config_to_form_utils.ts
@@ -41,6 +41,7 @@ function ingestConfigToFormik(
): FormikValues {
let ingestFormikValues = {} as FormikValues;
if (ingestConfig) {
+ ingestFormikValues['enabled'] = ingestConfig.enabled;
ingestFormikValues['docs'] = ingestDocs || getInitialValue('json');
ingestFormikValues['enrich'] = processorsConfigToFormik(
ingestConfig.enrich
diff --git a/public/utils/config_to_template_utils.ts b/public/utils/config_to_template_utils.ts
index 1cf4d80a..206441fc 100644
--- a/public/utils/config_to_template_utils.ts
+++ b/public/utils/config_to_template_utils.ts
@@ -11,7 +11,6 @@ import {
TemplateFlow,
TemplateEdge,
ModelFormValue,
- IndexMappings,
WORKFLOW_STEP_TYPE,
WorkflowConfig,
PROCESSOR_TYPE,
@@ -58,13 +57,15 @@ function configToProvisionTemplateFlow(config: WorkflowConfig): TemplateFlow {
(node) => node.type === WORKFLOW_STEP_TYPE.CREATE_SEARCH_PIPELINE_STEP_TYPE
) as CreateSearchPipelineNode;
- nodes.push(
- indexConfigToTemplateNode(
- config.ingest.index,
- createIngestPipelineNode,
- createSearchPipelineNode
- )
- );
+ if (config.ingest.enabled) {
+ nodes.push(
+ indexConfigToTemplateNode(
+ config.ingest.index,
+ createIngestPipelineNode,
+ createSearchPipelineNode
+ )
+ );
+ }
return {
nodes,
@@ -81,7 +82,7 @@ function ingestConfigToTemplateNodes(
);
const hasProcessors = ingestProcessors.length > 0;
- return hasProcessors
+ return hasProcessors && ingestConfig.enabled
? [
{
id: ingestPipelineName,
@@ -179,7 +180,17 @@ function indexConfigToTemplateNode(
ingestPipelineNode?: CreateIngestPipelineNode,
searchPipelineNode?: CreateSearchPipelineNode
): CreateIndexNode {
- let finalSettings = indexConfig.settings.value as {};
+ let finalSettings = {};
+ let finalMappings = {};
+ try {
+ // @ts-ignore
+ finalSettings = JSON.parse(indexConfig.settings?.value);
+ } catch (e) {}
+ try {
+ // @ts-ignore
+ finalMappings = JSON.parse(indexConfig.mappings?.value);
+ } catch (e) {}
+
let finalPreviousNodeInputs = {};
function updateFinalInputsAndSettings(
@@ -218,7 +229,7 @@ function indexConfigToTemplateNode(
index_name: indexConfig.name.value as string,
configurations: {
settings: finalSettings,
- mappings: indexConfig.mappings.value as IndexMappings,
+ mappings: finalMappings,
},
},
};
diff --git a/public/utils/form_to_config_utils.ts b/public/utils/form_to_config_utils.ts
index d124c122..6ab866f1 100644
--- a/public/utils/form_to_config_utils.ts
+++ b/public/utils/form_to_config_utils.ts
@@ -44,6 +44,7 @@ function formikToIngestUiConfig(
): IngestConfig {
return {
...existingConfig,
+ enabled: ingestFormValues['enabled'],
enrich: formikToProcessorsUiConfig(
ingestFormValues['enrich'],
existingConfig.enrich