Skip to content

Commit

Permalink
Multi-processor support & associated CRUD operations (#168)
Browse files Browse the repository at this point in the history
Signed-off-by: Tyler Ohlsen <[email protected]>
  • Loading branch information
ohltyler authored Jun 10, 2024
1 parent 2eb0bb9 commit 976cab2
Show file tree
Hide file tree
Showing 7 changed files with 153 additions and 62 deletions.
38 changes: 26 additions & 12 deletions public/pages/workflow_detail/resizable_workspace.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ import { useSelector } from 'react-redux';
import { useHistory } from 'react-router-dom';
import { Form, Formik } from 'formik';
import * as yup from 'yup';
import {
EuiFlexGroup,
EuiFlexItem,
EuiPanel,
EuiResizableContainer,
} from '@elastic/eui';
import { EuiFlexGroup, EuiFlexItem, EuiResizableContainer } from '@elastic/eui';
import { getCore } from '../../services';

import { Workflow, WorkflowFormValues, WorkflowSchema } from '../../../common';
import {
Workflow,
WorkflowConfig,
WorkflowFormValues,
WorkflowSchema,
} from '../../../common';
import { APP_PATH, uiConfigToFormik, uiConfigToSchema } from '../../utils';
import { AppState, setDirty, useAppDispatch } from '../../store';
import { WorkflowInputs } from './workflow_inputs';
Expand Down Expand Up @@ -55,6 +55,12 @@ export function ResizableWorkspace(props: ResizableWorkspaceProps) {
const [formValues, setFormValues] = useState<WorkflowFormValues>({});
const [formSchema, setFormSchema] = useState<WorkflowSchema>(yup.object({}));

// Temp UI config state. For persisting changes to the UI config that may
// not be saved in the backend (e.g., adding / removing an ingest processor)
const [uiConfig, setUiConfig] = useState<WorkflowConfig | undefined>(
undefined
);

// Workflow inputs side panel state
const [isWorkflowInputsPanelOpen, setIsWorkflowInputsPanelOpen] = useState<
boolean
Expand Down Expand Up @@ -101,15 +107,22 @@ export function ResizableWorkspace(props: ResizableWorkspaceProps) {
}
}, [props.workflow]);

// Initialize the form state to an existing workflow, if applicable.
// Initialize the form state based on the workflow's config, if applicable.
useEffect(() => {
if (workflow?.ui_metadata?.config) {
const initFormValues = uiConfigToFormik(workflow.ui_metadata.config);
const initFormSchema = uiConfigToSchema(workflow.ui_metadata.config);
setUiConfig(workflow.ui_metadata.config);
}
}, [workflow]);

// Initialize the form state based on the current UI config
useEffect(() => {
if (uiConfig) {
const initFormValues = uiConfigToFormik(uiConfig);
const initFormSchema = uiConfigToSchema(uiConfig);
setFormValues(initFormValues);
setFormSchema(initFormSchema);
}
}, [workflow]);
}, [uiConfig]);

/**
* Function to pass down to the Formik <Form> components as a listener to propagate
Expand Down Expand Up @@ -161,8 +174,9 @@ export function ResizableWorkspace(props: ResizableWorkspaceProps) {
>
<WorkflowInputs
workflow={props.workflow}
formikProps={formikProps}
onFormChange={onFormChange}
uiConfig={uiConfig}
setUiConfig={setUiConfig}
setIngestResponse={setIngestResponse}
/>
</EuiResizablePanel>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@
import React from 'react';
import { EuiFlexGroup, EuiFlexItem, EuiTitle } from '@elastic/eui';
import { ProcessorsList } from './processors_list';
import { Workflow } from '../../../../../common';
import { WorkflowConfig } from '../../../../../common';

interface EnrichDataProps {
workflow: Workflow;
onFormChange: () => void;
uiConfig: WorkflowConfig;
setUiConfig: (uiConfig: WorkflowConfig) => void;
}

/**
Expand All @@ -26,8 +27,9 @@ export function EnrichData(props: EnrichDataProps) {
</EuiFlexItem>
<EuiFlexItem>
<ProcessorsList
workflow={props.workflow}
onFormChange={props.onFormChange}
uiConfig={props.uiConfig}
setUiConfig={props.setUiConfig}
/>
</EuiFlexItem>
</EuiFlexGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,12 @@
*/

import React, { useEffect, useState } from 'react';
import {
EuiFlexGroup,
EuiFlexItem,
EuiRadioGroup,
EuiTitle,
} from '@elastic/eui';
import { IConfigField, Workflow } from '../../../../../common';
import { EuiFlexGroup, EuiFlexItem, EuiTitle } from '@elastic/eui';
import { IConfigField, WorkflowConfig } from '../../../../../common';
import { SelectField, TextField } from '../input_fields';

interface IngestDataProps {
workflow: Workflow;
uiConfig: WorkflowConfig;
onFormChange: () => void;
}

Expand All @@ -31,10 +26,7 @@ export function IngestData(props: IngestDataProps) {
</EuiFlexItem>
<EuiFlexItem>
<TextField
field={
props.workflow.ui_metadata?.config?.ingest?.index
?.name as IConfigField
}
field={props.uiConfig.ingest.index?.name as IConfigField}
fieldPath={'ingest.index.name'}
onFormChange={props.onFormChange}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ import { EuiFlexGroup, EuiFlexItem, EuiHorizontalRule } from '@elastic/eui';
import { SourceData } from './source_data';
import { EnrichData } from './enrich_data';
import { IngestData } from './ingest_data';
import { Workflow } from '../../../../../common';
import { WorkflowConfig } from '../../../../../common';

interface IngestInputsProps {
workflow: Workflow;
onFormChange: () => void;
ingestDocs: {}[];
setIngestDocs: (docs: {}[]) => void;
uiConfig: WorkflowConfig;
setUiConfig: (uiConfig: WorkflowConfig) => void;
}

/**
Expand All @@ -34,16 +35,17 @@ export function IngestInputs(props: IngestInputsProps) {
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EnrichData
workflow={props.workflow}
onFormChange={props.onFormChange}
uiConfig={props.uiConfig}
setUiConfig={props.setUiConfig}
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiHorizontalRule margin="none" />
</EuiFlexItem>
<EuiFlexItem grow={false}>
<IngestData
workflow={props.workflow}
uiConfig={props.uiConfig}
onFormChange={props.onFormChange}
/>
</EuiFlexItem>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,115 @@
*/

import React from 'react';
import { EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui';
import { IConfig, Workflow } from '../../../../../common';
import {
EuiButton,
EuiButtonIcon,
EuiFlexGroup,
EuiFlexItem,
EuiHorizontalRule,
EuiPanel,
EuiText,
} from '@elastic/eui';
import { cloneDeep } from 'lodash';
import { useFormikContext } from 'formik';
import {
IConfig,
PROCESSOR_TYPE,
WorkflowConfig,
WorkflowFormValues,
} from '../../../../../common';
import { ConfigFieldList } from '../config_field_list';
import { formikToUiConfig, generateId } from '../../../../utils';

interface ProcessorsListProps {
workflow: Workflow;
onFormChange: () => void;
uiConfig: WorkflowConfig;
setUiConfig: (uiConfig: WorkflowConfig) => void;
}

/**
* Input component for configuring ingest pipeline processors
*/
export function ProcessorsList(props: ProcessorsListProps) {
const { values } = useFormikContext<WorkflowFormValues>();

// Adding a processor to the config. Fetch the existing one
// (getting any updated/interim values along the way) and add to
// the list of processors
function addProcessor(processorIdToAdd: string): void {
const existingConfig = cloneDeep(props.uiConfig as WorkflowConfig);
let newConfig = formikToUiConfig(values, existingConfig);
newConfig.ingest.enrich.processors = [
...newConfig.ingest.enrich.processors,
{
type: PROCESSOR_TYPE.MODEL,
id: processorIdToAdd,
fields: [],
},
];
props.setUiConfig(newConfig);
}

// Deleting a processor from the config. Fetch the existing one
// (getting any updated/interim values along the way) delete
// the specified processor from the list of processors
function deleteProcessor(processorIdToDelete: string): void {
const existingConfig = cloneDeep(props.uiConfig as WorkflowConfig);
let newConfig = formikToUiConfig(values, existingConfig);
newConfig.ingest.enrich.processors = newConfig.ingest.enrich.processors.filter(
(processorConfig) => processorConfig.id !== processorIdToDelete
);
props.setUiConfig(newConfig);
}

return (
<EuiFlexGroup direction="column">
{props.workflow.ui_metadata?.config.ingest?.enrich.processors.map(
{props.uiConfig?.ingest.enrich.processors.map(
(processor: IConfig, processorIndex) => {
return (
<EuiFlexItem key={processorIndex}>
<EuiText>
{processor.metadata?.label || 'Ingest processor'}
</EuiText>
<ConfigFieldList
config={processor}
baseConfigPath="ingest.enrich"
onFormChange={props.onFormChange}
/>
<EuiPanel>
<EuiFlexGroup direction="row" justifyContent="spaceBetween">
<EuiFlexItem grow={false}>
<EuiText>
{processor.metadata?.label || 'Ingest processor'}
</EuiText>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButtonIcon
iconType={'trash'}
color="danger"
aria-label="Delete"
onClick={() => {
deleteProcessor(processor.id);
}}
/>
</EuiFlexItem>
</EuiFlexGroup>
<EuiHorizontalRule size="full" margin="s" />
<ConfigFieldList
config={processor}
baseConfigPath="ingest.enrich"
onFormChange={props.onFormChange}
/>
</EuiPanel>
</EuiFlexItem>
);
}
)}
<EuiFlexItem grow={false}>
<div>
<EuiButton
onClick={() => {
// TODO: enhance this to either choose from a list of preset
// processors, or at the least a usable generic processor
addProcessor(generateId('test-processor'));
}}
>
Add another processor
</EuiButton>
</div>
</EuiFlexItem>
</EuiFlexGroup>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ import { EuiFlexGroup, EuiFlexItem, EuiHorizontalRule } from '@elastic/eui';
import { ConfigureSearchRequest } from './configure_search_request';
import { EnrichSearchRequest } from './enrich_search_request';
import { EnrichSearchResponse } from './enrich_search_response';
import { Workflow } from '../../../../../common';
import { WorkflowConfig } from '../../../../../common';

interface SearchInputsProps {
workflow: Workflow;
uiConfig: WorkflowConfig;
}

/**
Expand Down
Loading

0 comments on commit 976cab2

Please sign in to comment.