diff --git a/client/src/pages/platform/workflow-editor/components/Properties/Property.tsx b/client/src/pages/platform/workflow-editor/components/Properties/Property.tsx index 43633cecdeb..1a4556cea66 100644 --- a/client/src/pages/platform/workflow-editor/components/Properties/Property.tsx +++ b/client/src/pages/platform/workflow-editor/components/Properties/Property.tsx @@ -2,6 +2,7 @@ import {DEFAULT_SCHEMA} from '@/components/JsonSchemaBuilder/utils/constants'; import {SchemaRecordType} from '@/components/JsonSchemaBuilder/utils/types'; import RequiredMark from '@/components/RequiredMark'; import {Label} from '@/components/ui/label'; +import {Skeleton} from '@/components/ui/skeleton'; import {Tooltip, TooltipContent, TooltipTrigger} from '@/components/ui/tooltip'; import InputTypeSwitchButton from '@/pages/platform/workflow-editor/components/Properties/components/InputTypeSwitchButton'; import PropertyCodeEditor from '@/pages/platform/workflow-editor/components/Properties/components/PropertyCodeEditor/PropertyCodeEditor'; @@ -22,6 +23,7 @@ import deleteProperty from '@/pages/platform/workflow-editor/utils/deletePropert import getInputHTMLType from '@/pages/platform/workflow-editor/utils/getInputHTMLType'; import saveProperty from '@/pages/platform/workflow-editor/utils/saveProperty'; import {Option} from '@/shared/middleware/platform/configuration'; +import {useGetWorkflowNodeParameterDisplayConditionsQuery} from '@/shared/queries/platform/workflowNodeParameters.queries'; import {ArrayPropertyType, PropertyAllType} from '@/shared/types'; import {QuestionMarkCircledIcon} from '@radix-ui/react-icons'; import {TooltipPortal} from '@radix-ui/react-tooltip'; @@ -122,6 +124,15 @@ const Property = ({ const {showPropertyCodeEditorSheet, showPropertyJsonSchemaBuilder, showWorkflowCodeEditorSheet} = useWorkflowEditorStore(); + const {isFetching: isFetchingDisplayConditions} = useGetWorkflowNodeParameterDisplayConditionsQuery( + { + id: workflow.id!, + // eslint-disable-next-line @typescript-eslint/no-non-null-asserted-optional-chain + workflowNodeName: currentNode?.workflowNodeName!, + }, + !!currentNode?.workflowNodeName + ); + const previousOperationName = usePrevious(currentNode?.operationName); const previousMentionInputValue = usePrevious(mentionInputValue); @@ -906,6 +917,16 @@ const Property = ({ return <>; } + if (displayCondition && currentComponent?.displayConditions?.[displayCondition] && isFetchingDisplayConditions) { + return ( +
+ + + +
+ ); + } + return (
  • >(); const [currentOperationName, setCurrentOperationName] = useState(''); const [currentOperationProperties, setCurrentOperationProperties] = useState>([]); - const [workflowDefinition, setWorkflowDefinition] = useState({}); const {currentComponent, currentNode, setCurrentComponent, setCurrentNode, workflowNodeDetailsPanelOpen} = useWorkflowNodeDetailsPanelStore(); @@ -102,7 +99,7 @@ const WorkflowNodeDetailsPanel = ({ const {data: currentComponentDefinition} = useGetComponentDefinitionQuery( { - componentName: currentNode?.componentName || currentNode?.id || '', + componentName: currentNode?.componentName || '', componentVersion: currentNode?.version || 1, }, !!currentNode && !currentNode.taskDispatcher @@ -111,7 +108,7 @@ const WorkflowNodeDetailsPanel = ({ const {data: workflowTestConfigurationConnections} = useGetWorkflowTestConfigurationConnectionsQuery( { workflowId: workflow.id as string, - workflowNodeName: currentNode?.name as string, + workflowNodeName: currentNode?.workflowNodeName as string, }, !!workflow.id && !!currentNode ); @@ -149,7 +146,7 @@ const WorkflowNodeDetailsPanel = ({ const {data: currentTaskDispatcherDefinition} = useGetTaskDispatcherDefinitionQuery( { - taskDispatcherName: currentNode?.componentName || currentNode?.id || '', + taskDispatcherName: currentNode?.componentName || '', taskDispatcherVersion: currentNode?.version || 1, }, !!currentNode && !!currentNode.taskDispatcher @@ -163,7 +160,7 @@ const WorkflowNodeDetailsPanel = ({ const {nodeNames} = workflow; - const currentNodeIndex = currentNode && nodeNames?.indexOf(currentNode?.name); + const currentNodeIndex = currentNode && nodeNames?.indexOf(currentNode?.workflowNodeName); const previousNodeNames = nodeNames.length > 1 ? nodeNames?.slice(0, currentNodeIndex) : []; @@ -191,8 +188,8 @@ const WorkflowNodeDetailsPanel = ({ ); const hasOutputData = currentNodeDefinition?.outputDefined; - const currentWorkflowTrigger = workflow.triggers?.find((trigger) => trigger.name === currentNode?.name); - const currentWorkflowTask = workflow.tasks?.find((task) => task.name === currentNode?.name); + const currentWorkflowTrigger = workflow.triggers?.find((trigger) => trigger.name === currentNode?.workflowNodeName); + const currentWorkflowTask = workflow.tasks?.find((task) => task.name === currentNode?.workflowNodeName); const componentConnections: WorkflowConnection[] = currentWorkflowTask?.connections || currentWorkflowTrigger?.connections || []; @@ -219,6 +216,20 @@ const WorkflowNodeDetailsPanel = ({ return true; }); + const currentTaskData = currentComponentDefinition || currentTaskDispatcherDefinition; + const currentOperationFetched = currentActionFetched || currentTriggerFetched; + + const operationDataMissing = + currentComponent?.operationName && (!matchingOperation?.name || !currentOperationFetched); + + const tabDataExists = + (!currentNode?.trigger && !currentNode?.taskDispatcher && currentActionFetched) || + currentNode?.taskDispatcher || + (currentNode?.trigger && + currentTriggerFetched && + nodeTabs.length > 1 && + currentNode.componentName !== 'manual'); + const queryClient = useQueryClient(); const handleOperationSelectChange = async (newOperationName: string) => { @@ -264,17 +275,18 @@ const WorkflowNodeDetailsPanel = ({ const {componentName, description, label, workflowNodeName} = currentComponent; - let nodeData = { + let nodeData: NodeDataType = { componentName, description, label, - name: workflowNodeName || currentNode?.name || '', + name: workflowNodeName || currentNode?.workflowNodeName || '', operationName: newOperationName, parameters: getParametersWithDefaultValues({ properties: operationData.properties as Array, }), trigger: currentNode?.trigger, type: `${componentName}/v${currentComponentDefinition.version}/${newOperationName}`, + workflowNodeName, }; if (currentNode?.conditionData) { @@ -312,7 +324,7 @@ const WorkflowNodeDetailsPanel = ({ return; } - const updatedRootConditionNode = updateConditionSubtask({ + nodeData = updateConditionSubtask({ conditionCase, conditionId: currentNode.conditionData.conditionId, nodeIndex: taskIndex, @@ -322,8 +334,6 @@ const WorkflowNodeDetailsPanel = ({ updatedParentConditionTask, workflow, }); - - nodeData = updatedRootConditionNode.data ?? (updatedRootConditionNode as NodeDataType); } } } @@ -426,6 +436,10 @@ const WorkflowNodeDetailsPanel = ({ if (activeTab === 'output' && !hasOutputData) { setActiveTab('description'); } + + if (activeTab === 'properties' && !operationDataMissing && !currentOperationProperties?.length) { + setActiveTab('description'); + } // eslint-disable-next-line react-hooks/exhaustive-deps }, [ activeTab, @@ -435,13 +449,6 @@ const WorkflowNodeDetailsPanel = ({ currentComponentDefinition?.name, ]); - // Close the panel if the current node is deleted - useEffect(() => { - if (!currentNode?.name || !nodeNames.includes(currentNode?.name)) { - useWorkflowNodeDetailsPanelStore.getState().reset(); - } - }, [currentNode?.name, nodeNames]); - // If the current component requires a connection, set the active tab to 'connection' useEffect(() => { if (currentComponentDefinition?.connectionRequired && !workflowTestConfigurationConnections?.length) { @@ -461,31 +468,6 @@ const WorkflowNodeDetailsPanel = ({ // eslint-disable-next-line react-hooks/exhaustive-deps }, [workflowTestConfigurationConnections]); - // Parse the workflow definition to an object - useEffect(() => { - if (workflow.definition) { - setWorkflowDefinition(JSON.parse(workflow.definition)); - } - }, [workflow.definition]); - - // Close the panel if the current node is deleted from the workflow definition - useEffect(() => { - if (currentNode?.trigger) { - return; - } - - if (!workflowDefinition.tasks) { - return; - } - - const taskNames = getAllTaskNames(workflowDefinition.tasks); - - if (currentNode && taskNames && !taskNames?.includes(currentNode?.name)) { - useWorkflowNodeDetailsPanelStore.getState().reset(); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [currentNode, workflowDefinition.tasks?.length]); - // Store new operationName into currentNode useEffect(() => { if (currentNode?.operationName && currentOperationName) { @@ -502,7 +484,7 @@ const WorkflowNodeDetailsPanel = ({ useEffect(() => { if (componentActions?.length) { const currentComponentAction = componentActions.find( - (action) => action.workflowNodeName === currentNode?.name + (action) => action.workflowNodeName === currentNode?.workflowNodeName ); if (currentComponentAction) { @@ -510,30 +492,16 @@ const WorkflowNodeDetailsPanel = ({ } } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [componentActions, currentNode?.name]); - - const currentTaskData = currentComponentDefinition || currentTaskDispatcherDefinition; - const currentOperationFetched = currentActionFetched || currentTriggerFetched; - - const operationDataMissing = - currentComponent?.operationName && (!matchingOperation?.name || !currentOperationFetched); + }, [componentActions, currentNode?.workflowNodeName]); - const tabDataExists = - (!currentNode?.trigger && !currentNode?.taskDispatcher && currentActionFetched) || - currentNode?.taskDispatcher || - (currentNode?.trigger && - currentTriggerFetched && - nodeTabs.length > 1 && - currentNode.componentName !== 'manual'); - - if (!workflowNodeDetailsPanelOpen || !currentNode?.name || !currentTaskData) { + if (!workflowNodeDetailsPanelOpen || !currentNode?.workflowNodeName || !currentTaskData) { return <>; } return (
    @@ -547,7 +515,7 @@ const WorkflowNodeDetailsPanel = ({ {currentNode?.label} - ({currentNode?.name}) + ({currentNode?.workflowNodeName}) {currentTaskData.description && ( @@ -639,7 +607,7 @@ const WorkflowNodeDetailsPanel = ({
    {activeTab === 'description' && ( )} @@ -652,29 +620,26 @@ const WorkflowNodeDetailsPanel = ({ currentComponentDefinition && ( )} {activeTab === 'properties' && - currentTaskData && - !operationDataMissing && - (currentOperationProperties?.length ? ( - - ) : ( -
    - Loading... -
    - ))} + !operationDataMissing && + currentOperationProperties?.length ? ( + + ) : ( +
    Loading...
    + )} {activeTab === 'output' && currentNode && currentComponentDefinition && ( diff --git a/client/src/pages/platform/workflow-editor/components/WorkflowNodesPopoverMenuOperationList.tsx b/client/src/pages/platform/workflow-editor/components/WorkflowNodesPopoverMenuOperationList.tsx index ba6d900d0c6..6cb7478b26a 100644 --- a/client/src/pages/platform/workflow-editor/components/WorkflowNodesPopoverMenuOperationList.tsx +++ b/client/src/pages/platform/workflow-editor/components/WorkflowNodesPopoverMenuOperationList.tsx @@ -1,7 +1,6 @@ import {useAnalytics} from '@/shared/hooks/useAnalytics'; import {ActionDefinitionApi, ComponentDefinition} from '@/shared/middleware/platform/configuration'; import {ActionDefinitionKeys} from '@/shared/queries/platform/actionDefinitions.queries'; -import {WorkflowNodeOutputKeys} from '@/shared/queries/platform/workflowNodeOutputs.queries'; import {ClickedOperationType, NodeDataType, PropertyAllType} from '@/shared/types'; import {getRandomId} from '@/shared/util/random-utils'; import {Component1Icon} from '@radix-ui/react-icons'; @@ -15,6 +14,7 @@ import useWorkflowDataStore from '../stores/useWorkflowDataStore'; import useWorkflowNodeDetailsPanelStore from '../stores/useWorkflowNodeDetailsPanelStore'; import getFormattedName from '../utils/getFormattedName'; import getParametersWithDefaultValues from '../utils/getParametersWithDefaultValues'; +import handleComponentAddedSuccess from '../utils/handleComponentAddedSuccess'; import handleConditionChildOperationClick from '../utils/handleConditionChildOperationClick'; import saveWorkflowDefinition from '../utils/saveWorkflowDefinition'; @@ -36,7 +36,7 @@ const WorkflowNodesPopoverMenuOperationList = ({ trigger, }: WorkflowNodesPopoverMenuOperationListProps) => { const {setLatestComponentDefinition, workflow} = useWorkflowDataStore(); - const {currentNode, setCurrentComponent, setCurrentNode} = useWorkflowNodeDetailsPanelStore(); + const {currentNode} = useWorkflowNodeDetailsPanelStore(); const {captureComponentUsed} = useAnalytics(); @@ -76,7 +76,7 @@ const WorkflowNodesPopoverMenuOperationList = ({ label: componentLabel, metadata: undefined, name: 'trigger_1', - operationName: operationName, + operationName, parameters: undefined, trigger: true, type: `${componentName}/v${version}/${operationName}`, @@ -86,30 +86,13 @@ const WorkflowNodesPopoverMenuOperationList = ({ saveWorkflowDefinition({ nodeData: newTriggerNodeData, - onSuccess: () => { - queryClient.invalidateQueries({ - queryKey: WorkflowNodeOutputKeys.filteredPreviousWorkflowNodeOutputs({ - id: workflow.id!, - lastWorkflowNodeName: currentNode?.name, - }), - }); - - if (currentNode?.trigger) { - setCurrentNode({ - ...currentNode, - ...newTriggerNodeData, - }); - } - - setCurrentComponent({ - componentName: newTriggerNodeData.componentName, - description: newTriggerNodeData.description, - label: newTriggerNodeData.label, - operationName: newTriggerNodeData.operationName, - type: newTriggerNodeData.type, - workflowNodeName: newTriggerNodeData.workflowNodeName ?? 'trigger_1', - }); - }, + onSuccess: () => + handleComponentAddedSuccess({ + currentNode, + nodeData: newTriggerNodeData, + queryClient, + workflow, + }), queryClient, updateWorkflowMutation, workflow, @@ -144,23 +127,27 @@ const WorkflowNodesPopoverMenuOperationList = ({ const workflowNodeName = getFormattedName(clickedOperation.componentName!, nodes); + const newWorkflowNodeData = { + componentName: clickedOperation.componentName, + icon: clickedOperation.icon && ( + } + src={clickedOperation.icon} + /> + ), + label: clickedOperation.componentLabel, + metadata: undefined, + name: workflowNodeName, + operationName: clickedOperation.operationName, + parameters: undefined, + type: clickedOperation.type, + version, + workflowNodeName, + }; + const newWorkflowNode = { - data: { - componentName: clickedOperation.componentName, - icon: clickedOperation.icon && ( - } - src={clickedOperation.icon} - /> - ), - label: clickedOperation.componentLabel, - metadata: {}, - name: workflowNodeName, - type: clickedOperation.type, - version, - workflowNodeName, - }, + data: newWorkflowNodeData, id: getRandomId(), position: { x: 0, @@ -179,20 +166,19 @@ const WorkflowNodesPopoverMenuOperationList = ({ saveWorkflowDefinition({ nodeData: { - ...newWorkflowNode.data, + ...newWorkflowNodeData, parameters: getParametersWithDefaultValues({ properties: clickedComponentActionDefinition?.properties as Array, }), }, nodeIndex: (previousWorkflowTaskIndex ?? 0) + 1, - onSuccess: () => { - queryClient.invalidateQueries({ - queryKey: WorkflowNodeOutputKeys.filteredPreviousWorkflowNodeOutputs({ - id: workflow.id!, - lastWorkflowNodeName: currentNode?.name, - }), - }); - }, + onSuccess: () => + handleComponentAddedSuccess({ + currentNode, + nodeData: newWorkflowNodeData, + queryClient, + workflow, + }), queryClient, updateWorkflowMutation, workflow, @@ -264,14 +250,13 @@ const WorkflowNodesPopoverMenuOperationList = ({ }), }, nodeIndex: taskNodeIndex, - onSuccess: () => { - queryClient.invalidateQueries({ - queryKey: WorkflowNodeOutputKeys.filteredPreviousWorkflowNodeOutputs({ - id: workflow.id!, - lastWorkflowNodeName: currentNode?.name, - }), - }); - }, + onSuccess: () => + handleComponentAddedSuccess({ + currentNode, + nodeData: newWorkflowNodeData, + queryClient, + workflow, + }), queryClient, updateWorkflowMutation, workflow, diff --git a/client/src/pages/platform/workflow-editor/components/node-details-tabs/OutputTab.tsx b/client/src/pages/platform/workflow-editor/components/node-details-tabs/OutputTab.tsx index cb8fa9a3cf4..8e11eb9b2c7 100644 --- a/client/src/pages/platform/workflow-editor/components/node-details-tabs/OutputTab.tsx +++ b/client/src/pages/platform/workflow-editor/components/node-details-tabs/OutputTab.tsx @@ -12,7 +12,7 @@ import { WorkflowNodeOutputKeys, useGetWorkflowNodeOutputQuery, } from '@/shared/queries/platform/workflowNodeOutputs.queries'; -import {NodeType, PropertyAllType} from '@/shared/types'; +import {NodeDataType, PropertyAllType} from '@/shared/types'; import {CaretDownIcon} from '@radix-ui/react-icons'; import {useQueryClient} from '@tanstack/react-query'; import {useCopyToClipboard} from '@uidotdev/usehooks'; @@ -24,7 +24,7 @@ import OutputTabSampleDataDialog from './OutputTabSampleDataDialog'; interface OutputTabProps { connectionMissing: boolean; - currentNode: NodeType; + currentNode: NodeDataType; outputDefined: boolean; workflowId: string; } diff --git a/client/src/pages/platform/workflow-editor/hooks/useHandleDrop.tsx b/client/src/pages/platform/workflow-editor/hooks/useHandleDrop.tsx index 00c63fd7076..12391766cb1 100644 --- a/client/src/pages/platform/workflow-editor/hooks/useHandleDrop.tsx +++ b/client/src/pages/platform/workflow-editor/hooks/useHandleDrop.tsx @@ -145,12 +145,9 @@ export default function useHandleDrop(): [ undefined ); - parameters = { - ...newWorkflowNode.data, - parameters: getParametersWithDefaultValues({ - properties: draggedComponentActionDefinition.properties || [], - }), - }; + parameters = getParametersWithDefaultValues({ + properties: draggedComponentActionDefinition.properties || [], + }); } let taskNodeIndex: number | undefined = undefined; @@ -279,12 +276,9 @@ export default function useHandleDrop(): [ undefined ); - parameters = { - ...newWorkflowNode.data, - parameters: getParametersWithDefaultValues({ - properties: draggedComponentActionDefinition.properties || [], - }), - }; + parameters = getParametersWithDefaultValues({ + properties: draggedComponentActionDefinition.properties || [], + }); } saveWorkflowDefinition({ diff --git a/client/src/pages/platform/workflow-editor/stores/useWorkflowNodeDetailsPanelStore.ts b/client/src/pages/platform/workflow-editor/stores/useWorkflowNodeDetailsPanelStore.ts index 2a41fb28daf..09eaf5ac24b 100644 --- a/client/src/pages/platform/workflow-editor/stores/useWorkflowNodeDetailsPanelStore.ts +++ b/client/src/pages/platform/workflow-editor/stores/useWorkflowNodeDetailsPanelStore.ts @@ -1,14 +1,14 @@ /* eslint-disable sort-keys */ -import {ComponentType, NodeType} from '@/shared/types'; +import {ComponentType, NodeDataType} from '@/shared/types'; import {create} from 'zustand'; import {devtools} from 'zustand/middleware'; -interface WorkflowNodeDetailsPanelStateI { +interface WorkflowNodeDetailsPanelStoreI { currentComponent: ComponentType | undefined; setCurrentComponent: (currentComponent: ComponentType | undefined) => void; - currentNode: NodeType | undefined; - setCurrentNode: (currentNode: NodeType | undefined) => void; + currentNode: NodeDataType | undefined; + setCurrentNode: (currentNode: NodeDataType | undefined) => void; // eslint-disable-next-line @typescript-eslint/no-explicit-any focusedInput: any; @@ -21,7 +21,7 @@ interface WorkflowNodeDetailsPanelStateI { setWorkflowNodeDetailsPanelOpen: (workflowNodeDetailsPanelOpen: boolean) => void; } -const useWorkflowNodeDetailsPanelStore = create()( +const useWorkflowNodeDetailsPanelStore = create()( devtools( (set) => ({ currentComponent: undefined, diff --git a/client/src/pages/platform/workflow-editor/utils/handleComponentAddedSuccess.ts b/client/src/pages/platform/workflow-editor/utils/handleComponentAddedSuccess.ts new file mode 100644 index 00000000000..d3460c03b77 --- /dev/null +++ b/client/src/pages/platform/workflow-editor/utils/handleComponentAddedSuccess.ts @@ -0,0 +1,52 @@ +import useWorkflowNodeDetailsPanelStore from '@/pages/platform/workflow-editor/stores/useWorkflowNodeDetailsPanelStore'; +import {Workflow} from '@/shared/middleware/automation/configuration'; +import {WorkflowNodeOutputKeys} from '@/shared/queries/platform/workflowNodeOutputs.queries'; +import {NodeDataType} from '@/shared/types'; +import {QueryClient} from '@tanstack/react-query'; + +interface HandleComponentAddedSuccessProps { + currentNode?: NodeDataType; + nodeData: NodeDataType; + queryClient: QueryClient; + workflow: Workflow; +} + +export default function handleComponentAddedSuccess({ + currentNode, + nodeData, + queryClient, + workflow, +}: HandleComponentAddedSuccessProps) { + queryClient.invalidateQueries({ + queryKey: WorkflowNodeOutputKeys.filteredPreviousWorkflowNodeOutputs({ + id: workflow.id!, + lastWorkflowNodeName: currentNode?.name, + }), + }); + + if (currentNode?.trigger && nodeData.trigger) { + useWorkflowNodeDetailsPanelStore.setState({ + ...useWorkflowNodeDetailsPanelStore.getState(), + currentNode: {...currentNode, ...nodeData}, + }); + } + + if (!currentNode?.trigger && !useWorkflowNodeDetailsPanelStore.getState().workflowNodeDetailsPanelOpen) { + useWorkflowNodeDetailsPanelStore.setState({ + ...useWorkflowNodeDetailsPanelStore.getState(), + currentNode: nodeData, + }); + } + + useWorkflowNodeDetailsPanelStore.setState({ + ...useWorkflowNodeDetailsPanelStore.getState(), + currentComponent: { + ...nodeData, + workflowNodeName: nodeData.workflowNodeName ?? 'trigger_1', + }, + }); + + useWorkflowNodeDetailsPanelStore.setState({ + workflowNodeDetailsPanelOpen: true, + }); +} diff --git a/client/src/pages/platform/workflow-editor/utils/handleConditionChildOperationClick.tsx b/client/src/pages/platform/workflow-editor/utils/handleConditionChildOperationClick.tsx index d9f4f927131..21b7967a1b2 100644 --- a/client/src/pages/platform/workflow-editor/utils/handleConditionChildOperationClick.tsx +++ b/client/src/pages/platform/workflow-editor/utils/handleConditionChildOperationClick.tsx @@ -1,7 +1,6 @@ import {Workflow} from '@/shared/middleware/automation/configuration'; import {ActionDefinition} from '@/shared/middleware/platform/configuration'; -import {WorkflowNodeOutputKeys} from '@/shared/queries/platform/workflowNodeOutputs.queries'; -import {ClickedOperationType, NodeType, PropertyAllType, UpdateWorkflowMutationType} from '@/shared/types'; +import {ClickedOperationType, NodeDataType, PropertyAllType, UpdateWorkflowMutationType} from '@/shared/types'; import {QueryClient} from '@tanstack/react-query'; import {ComponentIcon} from 'lucide-react'; import InlineSVG from 'react-inlinesvg'; @@ -10,11 +9,12 @@ import {Node} from 'reactflow'; import {WorkflowTaskDataType} from '../stores/useWorkflowDataStore'; import getFormattedName from './getFormattedName'; import getParametersWithDefaultValues from './getParametersWithDefaultValues'; +import handleComponentAddedSuccess from './handleComponentAddedSuccess'; import saveWorkflowDefinition from './saveWorkflowDefinition'; interface HandleConditionChildOperationClickProps { conditionId: string; - currentNode?: NodeType; + currentNode?: NodeDataType; nodes: Array; operation: ClickedOperationType; operationDefinition: ActionDefinition; @@ -61,14 +61,13 @@ export default function handleConditionChildOperationClick({ }), }, nodeIndex: taskAfterCurrentIndex, - onSuccess: () => { - queryClient.invalidateQueries({ - queryKey: WorkflowNodeOutputKeys.filteredPreviousWorkflowNodeOutputs({ - id: workflow.id!, - lastWorkflowNodeName: currentNode?.name, - }), - }); - }, + onSuccess: () => + handleComponentAddedSuccess({ + currentNode, + nodeData: newWorkflowNodeData, + queryClient, + workflow, + }), placeholderId, queryClient, updateWorkflowMutation, diff --git a/client/src/pages/platform/workflow-editor/utils/handleConditionClick.tsx b/client/src/pages/platform/workflow-editor/utils/handleConditionClick.tsx index 58bb2b98fa1..d2fd06b92fc 100644 --- a/client/src/pages/platform/workflow-editor/utils/handleConditionClick.tsx +++ b/client/src/pages/platform/workflow-editor/utils/handleConditionClick.tsx @@ -1,7 +1,6 @@ import {TaskDispatcherDefinitionApi, Workflow} from '@/shared/middleware/platform/configuration'; import {TaskDispatcherKeys} from '@/shared/queries/platform/taskDispatcherDefinitions.queries'; -import {WorkflowNodeOutputKeys} from '@/shared/queries/platform/workflowNodeOutputs.queries'; -import {ClickedDefinitionType, NodeType, PropertyAllType, UpdateWorkflowMutationType} from '@/shared/types'; +import {ClickedDefinitionType, NodeDataType, PropertyAllType, UpdateWorkflowMutationType} from '@/shared/types'; import {Component1Icon} from '@radix-ui/react-icons'; import {QueryClient} from '@tanstack/react-query'; import InlineSVG from 'react-inlinesvg'; @@ -10,11 +9,12 @@ import {Node} from 'reactflow'; import {WorkflowTaskDataType} from '../stores/useWorkflowDataStore'; import getFormattedName from './getFormattedName'; import getParametersWithDefaultValues from './getParametersWithDefaultValues'; +import handleComponentAddedSuccess from './handleComponentAddedSuccess'; import saveWorkflowDefinition from './saveWorkflowDefinition'; interface HandleConditionClickProps { clickedItem: ClickedDefinitionType; - currentNode?: NodeType; + currentNode?: NodeDataType; edge?: boolean; getNodes: () => Array; queryClient: QueryClient; @@ -53,7 +53,7 @@ export default async function handleConditionClick({ const workflowNodeName = getFormattedName(clickedItem.name!, nodes); - const newConditionNodeData = { + const newConditionNodeData: NodeDataType = { ...clickedTaskDispatcherDefinition, componentName: clickedItem.name, icon: ( @@ -69,6 +69,7 @@ export default async function handleConditionClick({ name: workflowNodeName, taskDispatcher: true, type: `${clickedTaskDispatcherDefinition.name}/v${clickedTaskDispatcherDefinition.version}`, + workflowNodeName, }; const {tasks} = workflow; @@ -110,16 +111,16 @@ export default async function handleConditionClick({ caseFalse: [], caseTrue: [], }, + workflowNodeName, }, nodeIndex: taskIndex, - onSuccess: () => { - queryClient.invalidateQueries({ - queryKey: WorkflowNodeOutputKeys.filteredPreviousWorkflowNodeOutputs({ - id: workflow.id!, - lastWorkflowNodeName: currentNode?.name, - }), - }); - }, + onSuccess: () => + handleComponentAddedSuccess({ + currentNode, + nodeData: newConditionNodeData, + queryClient, + workflow, + }), placeholderId: sourceNodeId, queryClient, updateWorkflowMutation, diff --git a/client/src/pages/platform/workflow-editor/utils/handleDeleteTask.ts b/client/src/pages/platform/workflow-editor/utils/handleDeleteTask.ts index 40506305750..361fcf9788a 100644 --- a/client/src/pages/platform/workflow-editor/utils/handleDeleteTask.ts +++ b/client/src/pages/platform/workflow-editor/utils/handleDeleteTask.ts @@ -4,7 +4,7 @@ import {WorkflowNodeOutputKeys} from '@/shared/queries/platform/workflowNodeOutp import { ComponentType, ConditionTaskDispatcherType, - NodeType, + NodeDataType, WorkflowDefinitionType, WorkflowTaskType, } from '@/shared/types'; @@ -12,17 +12,18 @@ import {QueryClient, UseMutationResult} from '@tanstack/react-query'; import {Node, NodeProps} from 'reactflow'; import {WorkflowTaskDataType} from '../stores/useWorkflowDataStore'; +import useWorkflowNodeDetailsPanelStore from '../stores/useWorkflowNodeDetailsPanelStore'; import getParentConditionTask from './getParentConditionTask'; interface HandleDeleteTaskProps { currentComponent?: ComponentType; - currentNode?: NodeType; + currentNode?: NodeDataType; data: NodeProps['data']; getNode: (id: string) => Node | undefined; id: string; queryClient: QueryClient; setCurrentComponent: (component: ComponentType | undefined) => void; - setCurrentNode: (node: NodeType | undefined) => void; + setCurrentNode: (node: NodeDataType | undefined) => void; updateWorkflowMutation: UseMutationResult; workflow: Workflow & WorkflowTaskDataType; } @@ -127,6 +128,8 @@ export default function handleDeleteTask({ if (currentNode?.name === data.name) { setCurrentNode(undefined); + + useWorkflowNodeDetailsPanelStore.getState().setWorkflowNodeDetailsPanelOpen(false); } if (currentComponent?.workflowNodeName === data.name) { diff --git a/client/src/pages/platform/workflow-editor/utils/updateRootConditionNode.ts b/client/src/pages/platform/workflow-editor/utils/updateRootConditionNode.ts index 0f5d4b2a423..2daf3ffdca9 100644 --- a/client/src/pages/platform/workflow-editor/utils/updateRootConditionNode.ts +++ b/client/src/pages/platform/workflow-editor/utils/updateRootConditionNode.ts @@ -1,5 +1,5 @@ import {Workflow, WorkflowTask} from '@/shared/middleware/automation/configuration'; -import {NodeType} from '@/shared/types'; +import {NodeDataType} from '@/shared/types'; import {Node} from 'reactflow'; import {WorkflowTaskDataType} from '../stores/useWorkflowDataStore'; @@ -10,7 +10,7 @@ interface UpdateRootConditionNodeProps { conditionId: string; nodeIndex: number; tasks: Array; - updatedParentConditionNodeData: NodeType; + updatedParentConditionNodeData: NodeDataType; updatedParentConditionTask: WorkflowTask; nodes: Array; workflow: Workflow & WorkflowTaskDataType; @@ -23,7 +23,7 @@ export default function updateRootConditionNode({ updatedParentConditionNodeData, updatedParentConditionTask, workflow, -}: UpdateRootConditionNodeProps): NodeType { +}: UpdateRootConditionNodeProps): NodeDataType { let currentTaskNode = updatedParentConditionNodeData; let currentTaskNodeConditionData = updatedParentConditionNodeData.conditionData; @@ -48,7 +48,7 @@ export default function updateRootConditionNode({ const workflowTasks = workflow.tasks; - let currentTask = workflowTasks?.find((task) => task.name === currentTaskNode.id); + let currentTask = workflowTasks?.find((task) => task.name === currentTaskNode.componentName); if (!currentTask) { currentTask = updatedParentConditionTask; @@ -69,6 +69,7 @@ export default function updateRootConditionNode({ currentTaskNode = { ...parentConditionTaskNode, + componentName: parentConditionTaskNode.data.componentName, name: parentConditionTaskNode.id, type: parentConditionTaskNode.type || 'workflow', version: parentConditionTaskNode.data.type.split('/v')[1], diff --git a/client/src/shared/types.ts b/client/src/shared/types.ts index 87a843fbda3..17def87c7dc 100644 --- a/client/src/shared/types.ts +++ b/client/src/shared/types.ts @@ -24,7 +24,6 @@ import { } from '@/shared/middleware/platform/configuration'; import {UseMutationResult} from '@tanstack/react-query'; import {ReactNode} from 'react'; -import {Node} from 'reactflow'; export type DataPillType = { componentName?: string; @@ -104,7 +103,13 @@ export type ClickedOperationType = { export type NodeDataType = { componentName: string; + conditionData?: { + conditionCase: string; + conditionId: string; + index: number; + }; connections?: Array; + connectionId?: number; description?: string; icon?: JSX.Element | ReactNode | string; label?: string; @@ -121,44 +126,8 @@ export type NodeDataType = { trigger?: boolean; type?: string; version?: number; - workflowNodeName?: string; -}; - -export type NodeType = { - componentName?: string; - conditionData?: { - conditionCase: string; - conditionId: string; - index: number; - }; - connections?: Array; - connectionId?: number; - data: NodeDataType; - displayConditions?: { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - [key: string]: boolean; - }; - metadata?: { - ui?: { - condition?: string; - dynamicPropertyTypes?: {[key: string]: string}; - }; - }; - icon?: ReactNode; - id: string; - label?: string; - name: string; - operationName?: string; - parameters?: { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - [key: string]: any; - }; - taskDispatcher?: boolean; - trigger?: boolean; - type: string; - version: number; workflowNodeName: string; -} & Node; +}; export type SubPropertyType = PropertyAllType & {custom: boolean};