diff --git a/public/component_types/interfaces.ts b/public/component_types/interfaces.ts index ee8bf0e3..e256e1cd 100644 --- a/public/component_types/interfaces.ts +++ b/public/component_types/interfaces.ts @@ -22,7 +22,6 @@ export type WorkspaceFormValues = { export type WorkspaceSchemaObj = { [componentId: string]: ObjectSchema; }; - export type WorkspaceSchema = ObjectSchema; /** diff --git a/public/pages/workflow_detail/workspace/resizable_workspace.tsx b/public/pages/workflow_detail/workspace/resizable_workspace.tsx index ecabbdf4..05c3bb3f 100644 --- a/public/pages/workflow_detail/workspace/resizable_workspace.tsx +++ b/public/pages/workflow_detail/workspace/resizable_workspace.tsx @@ -6,14 +6,14 @@ import React, { useRef, useState, useEffect } from 'react'; import { ReactFlowProvider } from 'reactflow'; import { Form, Formik } from 'formik'; -import { ObjectSchema } from 'yup'; import * as yup from 'yup'; import { EuiButton, EuiResizableContainer } from '@elastic/eui'; import { Workflow, WorkspaceFormValues, - WorkspaceSchemaObj, WorkspaceSchema, + ReactFlowComponent, + WorkspaceSchemaObj, componentDataToFormik, getComponentSchema, } from '../../../../common'; @@ -60,23 +60,33 @@ export function ResizableWorkspace(props: ResizableWorkspaceProps) { } }, [props.workflow]); - // If a component is added or deleted in the workspace, we update the values. - // However, we cannot dynamically update the schema due to this known - // formik bug: https://github.com/jaredpalmer/formik/issues/3335 - // So, we trigger this during validation when there is a mismatch - // in the count of component ids - function onComponentChange(values: WorkspaceFormValues): void { - const updatedComponentIds = Object.keys(values); - const newSchemaObj = {} as WorkspaceSchemaObj; + // Update the form values and validation schema when a node is added + // or removed from the workspace + function onNodesChange(nodes: ReactFlowComponent[]): void { + const updatedComponentIds = nodes.map((node) => node.id); + const existingComponentIds = Object.keys(formValues); + const updatedSchemaObj = {} as WorkspaceSchemaObj; + + if (updatedComponentIds.length > existingComponentIds.length) { + // TODO: implement for when a node is added + } else if (updatedComponentIds.length < existingComponentIds.length) { + existingComponentIds.forEach((existingId) => { + if (updatedComponentIds.includes(existingId)) { + updatedSchemaObj[existingId] = formSchema.fields[ + `${existingId}` + ] as yup.ObjectSchema; + } else { + delete formValues[`${existingId}`]; + } + }); + } else { + // if it is somehow triggered without node changes, be sure + // to prevent updating the form or schema + return; + } - Object.keys(formSchema.fields).forEach((componentId) => { - if (updatedComponentIds.includes(componentId)) { - newSchemaObj[componentId] = formSchema.fields[ - `${componentId}` - ] as ObjectSchema; - } - }); - setFormSchema(yup.object(newSchemaObj)); + const updatedSchema = yup.object(updatedSchemaObj) as WorkspaceSchema; + setFormSchema(updatedSchema); } return ( @@ -89,11 +99,6 @@ export function ResizableWorkspace(props: ResizableWorkspaceProps) { }} validate={(values) => { console.log('values on validate: ', values); - const componentCountValues = Object.keys(values).length; - const componentCountSchema = Object.keys(formSchema.fields).length; - if (componentCountSchema !== componentCountValues) { - onComponentChange(values); - } }} > {(formikProps) => ( @@ -111,7 +116,10 @@ export function ResizableWorkspace(props: ResizableWorkspaceProps) { return ( - + void; } const nodeTypes = { customComponent: WorkspaceComponent }; @@ -39,9 +46,17 @@ export function Workspace(props: WorkspaceProps) { const reactFlowWrapper = useRef(null); const { reactFlowInstance, setReactFlowInstance } = useContext(rfContext); - const [nodes, setNodes, onNodesChange] = useNodesState([]); + const [nodes, setNodes, onNodesChange] = useNodesState([]); const [edges, setEdges, onEdgesChange] = useEdgesState([]); + // Listener for node additions or deletions to propagate to parent component + const nodesLength = useStore( + (state) => Array.from(state.nodeInternals.values()).length || 0 + ); + useEffect(() => { + props.onNodesChange(nodes); + }, [nodesLength]); + const onConnect = useCallback( (params) => { const edge = { diff --git a/public/pages/workflow_detail/workspace_component/workspace_component.tsx b/public/pages/workflow_detail/workspace_component/workspace_component.tsx index 17f0b8b7..3c96d739 100644 --- a/public/pages/workflow_detail/workspace_component/workspace_component.tsx +++ b/public/pages/workflow_detail/workspace_component/workspace_component.tsx @@ -30,7 +30,6 @@ interface WorkspaceComponentProps { export function WorkspaceComponent(props: WorkspaceComponentProps) { const component = props.data; const { deleteNode } = useContext(rfContext); - const { values, validateForm } = useFormikContext(); return ( { deleteNode(component.id); - delete values[`${component.id}`]; - validateForm(); - // TODO: use below way instead of hacky change via validation. - // Formik bug reference: https://github.com/jaredpalmer/formik/issues/3335 - // delete validationSchema[`${component.id}`]; }} aria-label="Delete" />