diff --git a/client/src/pages/platform/connection/components/ConnectionParameters.tsx b/client/src/pages/platform/connection/components/ConnectionParameters.tsx index c3cce02ff1..b4da4d873a 100644 --- a/client/src/pages/platform/connection/components/ConnectionParameters.tsx +++ b/client/src/pages/platform/connection/components/ConnectionParameters.tsx @@ -1,4 +1,5 @@ import {ConnectionDefinition} from '@/shared/middleware/platform/configuration'; +import {Fragment} from 'react'; const ConnectionParameters = ({ authorizationParameters, @@ -54,7 +55,7 @@ const ConnectionParameters = ({ {hasAuthorizationParameters && existingAuthorizations.map((authorization) => ( - <> +
  • Authorization: @@ -73,7 +74,7 @@ const ConnectionParameters = ({
  • ))} - +
    ))} 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 1533d2c261..c79c38fcc2 100644 --- a/client/src/pages/platform/workflow-editor/components/Properties/Property.tsx +++ b/client/src/pages/platform/workflow-editor/components/Properties/Property.tsx @@ -18,6 +18,7 @@ import useWorkflowNodeDetailsPanelStore from '@/pages/platform/workflow-editor/s import deleteProperty from '@/pages/platform/workflow-editor/utils/deleteProperty'; import getInputHTMLType from '@/pages/platform/workflow-editor/utils/getInputHTMLType'; import saveProperty from '@/pages/platform/workflow-editor/utils/saveProperty'; +import {PATH_SPACE_REPLACEMENT} from '@/shared/constants'; import {Option} from '@/shared/middleware/platform/configuration'; import {PropertyAllType} from '@/shared/types'; import {QuestionMarkCircledIcon} from '@radix-ui/react-icons'; @@ -33,6 +34,7 @@ import {twMerge} from 'tailwind-merge'; import {useDebouncedCallback} from 'use-debounce'; import useWorkflowEditorStore from '../../stores/useWorkflowEditorStore'; +import replaceSpacesInKeys from '../../utils/replaceSpacesInObjectKeys'; import ArrayProperty from './ArrayProperty'; import ObjectProperty from './ObjectProperty'; @@ -176,6 +178,10 @@ const Property = ({ }); } + if (path?.includes(' ')) { + path = path.replace(/\s/g, PATH_SPACE_REPLACEMENT); + } + const getComponentIcon = (mentionValue: string) => { let componentName = mentionValue.split('_')[0].replace('${', ''); @@ -539,12 +545,14 @@ const Property = ({ return; } - const paramValue = resolvePath(parameters, path); + const formattedParamaters = replaceSpacesInKeys(parameters); + + const paramValue = resolvePath(formattedParamaters, path); if (paramValue !== undefined || paramValue !== null) { setPropertyParameterValue(paramValue); } else { - setPropertyParameterValue(parameters[name]); + setPropertyParameterValue(formattedParamaters[name]); } } // eslint-disable-next-line react-hooks/exhaustive-deps @@ -656,7 +664,10 @@ const Property = ({ } const optionsLookupDependsOnValues = optionsDataSource?.optionsLookupDependsOn.map((optionLookupDependency) => - resolvePath(currentComponent?.parameters, optionLookupDependency)?.toString() + resolvePath( + currentComponent?.parameters, + optionLookupDependency.replace('[index]', `[${arrayIndex}]`) + )?.toString() ); setLookupDependsOnValues(optionsLookupDependsOnValues); @@ -669,7 +680,10 @@ const Property = ({ const propertiesLookupDependsOnValues = propertiesDataSource?.propertiesLookupDependsOn.map( (propertyLookupDependency) => - resolvePath(currentComponent?.parameters, propertyLookupDependency)?.toString() + resolvePath( + currentComponent?.parameters, + propertyLookupDependency.replace('[index]', `[${arrayIndex}]`) + )?.toString() ); setLookupDependsOnValues(propertiesLookupDependsOnValues); diff --git a/client/src/pages/platform/workflow-editor/components/Properties/components/PropertyDynamicProperties.tsx b/client/src/pages/platform/workflow-editor/components/Properties/components/PropertyDynamicProperties.tsx index 8db74a93bf..d10585ccca 100644 --- a/client/src/pages/platform/workflow-editor/components/Properties/components/PropertyDynamicProperties.tsx +++ b/client/src/pages/platform/workflow-editor/components/Properties/components/PropertyDynamicProperties.tsx @@ -71,7 +71,10 @@ const PropertyDynamicProperties = ({ operationName={currentOperationName} parameterValue={property.name ? parameterValue?.[property.name] : ''} path={path} - property={property} + property={{ + ...property, + defaultValue: property.name ? parameterValue?.[property.name] : '', + }} /> ))} diff --git a/client/src/pages/platform/workflow-editor/components/WorkflowNodeDetailsPanel.tsx b/client/src/pages/platform/workflow-editor/components/WorkflowNodeDetailsPanel.tsx index 67d60436a6..a504f462a4 100644 --- a/client/src/pages/platform/workflow-editor/components/WorkflowNodeDetailsPanel.tsx +++ b/client/src/pages/platform/workflow-editor/components/WorkflowNodeDetailsPanel.tsx @@ -6,16 +6,26 @@ import {Tooltip, TooltipContent, TooltipTrigger} from '@/components/ui/tooltip'; import Properties from '@/pages/platform/workflow-editor/components/Properties/Properties'; import DataStreamComponentsTab from '@/pages/platform/workflow-editor/components/node-details-tabs/DataStreamComponentsTab'; import { + ActionDefinitionApi, ComponentDefinition, ComponentDefinitionBasic, + GetComponentActionDefinitionRequest, + GetComponentTriggerDefinitionRequest, + TriggerDefinitionApi, WorkflowConnection, WorkflowNodeOutput, } from '@/shared/middleware/platform/configuration'; import {useDeleteWorkflowNodeTestOutputMutation} from '@/shared/mutations/platform/workflowNodeTestOutputs.mutations'; -import {useGetComponentActionDefinitionQuery} from '@/shared/queries/platform/actionDefinitions.queries'; +import { + ActionDefinitionKeys, + useGetComponentActionDefinitionQuery, +} from '@/shared/queries/platform/actionDefinitions.queries'; import {useGetComponentDefinitionQuery} from '@/shared/queries/platform/componentDefinitions.queries'; import {useGetTaskDispatcherDefinitionQuery} from '@/shared/queries/platform/taskDispatcherDefinitions.queries'; -import {useGetTriggerDefinitionQuery} from '@/shared/queries/platform/triggerDefinitions.queries'; +import { + TriggerDefinitionKeys, + useGetTriggerDefinitionQuery, +} from '@/shared/queries/platform/triggerDefinitions.queries'; import {WorkflowNodeDynamicPropertyKeys} from '@/shared/queries/platform/workflowNodeDynamicProperties.queries'; import {WorkflowNodeOptionKeys} from '@/shared/queries/platform/workflowNodeOptions.queries'; import {WorkflowNodeOutputKeys} from '@/shared/queries/platform/workflowNodeOutputs.queries'; @@ -110,7 +120,7 @@ const WorkflowNodeDetailsPanel = ({ const {data: currentActionDefinition, isFetched: currentActionFetched} = useGetComponentActionDefinitionQuery( { - actionName: currentOperationName, + actionName: currentNode?.operationName ?? currentOperationName, componentName: currentComponentDefinition?.name as string, componentVersion: currentComponentDefinition?.version as number, }, @@ -216,7 +226,9 @@ const WorkflowNodeDetailsPanel = ({ const queryClient = useQueryClient(); - const handleOperationSelectChange = (newOperationName: string) => { + const handleOperationSelectChange = async (newOperationName: string) => { + setCurrentOperationName(newOperationName); + if (!currentComponentDefinition || !currentComponent) { return; } @@ -229,17 +241,43 @@ const WorkflowNodeDetailsPanel = ({ queryKey: WorkflowNodeOptionKeys.workflowNodeOptions, }); - const {componentName, notes, title, workflowNodeName} = currentComponent; + let operationData; + + if (currentNode?.trigger) { + const triggerDefinitionRequest: GetComponentTriggerDefinitionRequest = { + componentName: currentComponentDefinition?.name, + componentVersion: currentComponentDefinition?.version, + triggerName: newOperationName, + }; + + operationData = await queryClient.fetchQuery({ + queryFn: () => new TriggerDefinitionApi().getComponentTriggerDefinition(triggerDefinitionRequest), + queryKey: TriggerDefinitionKeys.triggerDefinition(triggerDefinitionRequest), + }); + } else { + const componentActionDefinitionRequest: GetComponentActionDefinitionRequest = { + actionName: newOperationName, + componentName: currentComponentDefinition.name, + componentVersion: currentComponentDefinition.version, + }; + + operationData = await queryClient.fetchQuery({ + queryFn: () => new ActionDefinitionApi().getComponentActionDefinition(componentActionDefinitionRequest), + queryKey: ActionDefinitionKeys.actionDefinition(componentActionDefinitionRequest), + }); + } + + const {componentName, description, label, workflowNodeName} = currentComponent; saveWorkflowDefinition({ nodeData: { componentName, - description: notes, - label: title, + description, + label, name: workflowNodeName || currentNode?.name || '', operationName: newOperationName, parameters: getParametersWithDefaultValues({ - properties: currentOperationProperties as Array, + properties: operationData.properties as Array, }), trigger: currentNode?.trigger, type: `${componentName}/v${currentComponentDefinition.version}/${newOperationName}`, @@ -253,10 +291,9 @@ const WorkflowNodeDetailsPanel = ({ parameters: getParametersWithDefaultValues({ properties: currentOperationProperties as Array, }), + type: `${componentName}/v${currentComponentDefinition.version}/${newOperationName}`, }); - setCurrentOperationName(newOperationName); - const formattedComponentActions = componentActions.map((componentAction) => { if (componentAction.workflowNodeName === currentNode?.name) { return { @@ -403,6 +440,7 @@ const WorkflowNodeDetailsPanel = ({ setCurrentNode({ ...currentNode, operationName: currentOperationName, + type: `${currentComponent?.componentName}/v${currentComponentDefinition?.version}/${currentOperationName}`, }); } // eslint-disable-next-line react-hooks/exhaustive-deps @@ -422,13 +460,6 @@ const WorkflowNodeDetailsPanel = ({ // eslint-disable-next-line react-hooks/exhaustive-deps }, [componentActions, currentNode?.name]); - useEffect(() => { - if (!currentOperationName || !matchingOperation?.name) { - setCurrentOperationName(currentNode?.operationName || currentComponentDefinition?.actions?.[0]?.name || ''); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [currentNode?.name, matchingOperation?.name]); - const currentTaskData = currentComponentDefinition || currentTaskDispatcherDefinition; const currentOperationFetcher = currentActionFetched || currentTriggerFetched; diff --git a/client/src/pages/platform/workflow-editor/components/WorkflowNodesPopoverMenuOperationList.tsx b/client/src/pages/platform/workflow-editor/components/WorkflowNodesPopoverMenuOperationList.tsx index 320fc9bff9..b2ebb03481 100644 --- a/client/src/pages/platform/workflow-editor/components/WorkflowNodesPopoverMenuOperationList.tsx +++ b/client/src/pages/platform/workflow-editor/components/WorkflowNodesPopoverMenuOperationList.tsx @@ -110,9 +110,9 @@ const WorkflowNodesPopoverMenuOperationList = ({ setCurrentComponent({ componentName: newTriggerNodeData.componentName, - notes: newTriggerNodeData.description, + description: newTriggerNodeData.description, + label: newTriggerNodeData.label, operationName: newTriggerNodeData.operationName, - title: newTriggerNodeData.label, type: newTriggerNodeData.type, workflowNodeName: newTriggerNodeData.workflowNodeName ?? 'trigger_1', }); diff --git a/client/src/pages/platform/workflow-editor/components/node-details-tabs/DescriptionTab.tsx b/client/src/pages/platform/workflow-editor/components/node-details-tabs/DescriptionTab.tsx index dec5cb3b9e..d9da731f06 100644 --- a/client/src/pages/platform/workflow-editor/components/node-details-tabs/DescriptionTab.tsx +++ b/client/src/pages/platform/workflow-editor/components/node-details-tabs/DescriptionTab.tsx @@ -3,7 +3,7 @@ import {Label} from '@/components/ui/label'; import {Textarea} from '@/components/ui/textarea'; import useWorkflowDataStore from '@/pages/platform/workflow-editor/stores/useWorkflowDataStore'; import useWorkflowNodeDetailsPanelStore from '@/pages/platform/workflow-editor/stores/useWorkflowNodeDetailsPanelStore'; -import {NodeDataType, UpdateWorkflowMutationType} from '@/shared/types'; +import {ComponentType, UpdateWorkflowMutationType} from '@/shared/types'; import {useQueryClient} from '@tanstack/react-query'; import {ChangeEvent} from 'react'; import {useDebouncedCallback} from 'use-debounce'; @@ -16,16 +16,9 @@ const DescriptionTab = ({updateWorkflowMutation}: {updateWorkflowMutation: Updat const queryClient = useQueryClient(); - const componentData: NodeDataType = { - componentName: currentComponent!.componentName!, - description: currentComponent?.notes, - icon: currentNode?.icon, - label: currentComponent?.title, - name: currentNode!.workflowNodeName!, - operationName: currentComponent?.operationName, - trigger: !!currentNode?.trigger, - type: currentComponent?.type, - workflowNodeName: currentNode?.workflowNodeName, + const componentData: ComponentType = { + ...currentComponent!, + workflowNodeName: currentNode!.workflowNodeName, }; const handleLabelChange = useDebouncedCallback((event: ChangeEvent) => { @@ -34,11 +27,12 @@ const DescriptionTab = ({updateWorkflowMutation}: {updateWorkflowMutation: Updat } saveWorkflowDefinition({ - nodeData: {...componentData, label: event.target.value}, + decorative: true, + nodeData: {...currentComponent!, label: event.target.value, name: currentComponent.workflowNodeName}, onSuccess: () => setCurrentComponent({ ...currentComponent, - title: event.target.value, + label: event.target.value, }), queryClient, updateWorkflowMutation, @@ -52,11 +46,12 @@ const DescriptionTab = ({updateWorkflowMutation}: {updateWorkflowMutation: Updat } saveWorkflowDefinition({ - nodeData: {...componentData, description: event.target.value}, + decorative: true, + nodeData: {...componentData, description: event.target.value, name: currentComponent.workflowNodeName}, onSuccess: () => setCurrentComponent({ ...currentComponent, - notes: event.target.value, + description: event.target.value, }), queryClient, updateWorkflowMutation, @@ -70,7 +65,7 @@ const DescriptionTab = ({updateWorkflowMutation}: {updateWorkflowMutation: Updat { + if (key.includes(' ')) { + const newKey = key.replace(/\s/g, PATH_SPACE_REPLACEMENT); + + parameters[newKey] = parameters[key]; + + delete parameters[key]; + } + + if (typeof parameters[key] === 'object' && parameters[key] !== null) { + replaceSpacesInKeys(parameters[key] as {[key: string]: unknown}); + } + }); + + return parameters; +} diff --git a/client/src/pages/platform/workflow-editor/utils/saveProperty.ts b/client/src/pages/platform/workflow-editor/utils/saveProperty.ts index 954e045d76..6e930bb477 100644 --- a/client/src/pages/platform/workflow-editor/utils/saveProperty.ts +++ b/client/src/pages/platform/workflow-editor/utils/saveProperty.ts @@ -1,3 +1,4 @@ +import {PATH_SPACE_REPLACEMENT} from '@/shared/constants'; import { UpdateWorkflowNodeParameter200Response, UpdateWorkflowNodeParameterOperationRequest, @@ -36,6 +37,10 @@ export default function saveProperty({ }: SavePropertyProps) { const {workflowNodeName} = currentComponent; + if (path.includes(PATH_SPACE_REPLACEMENT)) { + path = path.replace(new RegExp(PATH_SPACE_REPLACEMENT, 'g'), ' '); + } + updateWorkflowNodeParameterMutation.mutate( { id: workflowId, diff --git a/client/src/pages/platform/workflow-editor/utils/saveWorkflowDefinition.ts b/client/src/pages/platform/workflow-editor/utils/saveWorkflowDefinition.ts index b05fd97fc2..bd7dc372f8 100644 --- a/client/src/pages/platform/workflow-editor/utils/saveWorkflowDefinition.ts +++ b/client/src/pages/platform/workflow-editor/utils/saveWorkflowDefinition.ts @@ -21,6 +21,7 @@ type UpdateWorkflowRequestType = { interface SaveWorkflowDefinitionProps { conditionId?: string; + decorative?: boolean; nodeData: NodeDataType; nodeIndex?: number; onSuccess?: () => void; @@ -32,6 +33,7 @@ interface SaveWorkflowDefinitionProps { export default async function saveWorkflowDefinition({ conditionId, + decorative, nodeData, nodeIndex, onSuccess, @@ -127,6 +129,7 @@ export default async function saveWorkflowDefinition({ if ( existingWorkflowTask && + !decorative && (!operationName || (existingWorkflowTask.parameters && JSON.stringify(existingWorkflowTask.parameters) === JSON.stringify(newTask.parameters))) && diff --git a/client/src/shared/constants.ts b/client/src/shared/constants.ts index 5dad197a7e..82487ea73c 100644 --- a/client/src/shared/constants.ts +++ b/client/src/shared/constants.ts @@ -29,3 +29,5 @@ export const EDGE_STYLES = { stroke: STROKE_GRAY_300, strokeWidth: 2, }; + +export const PATH_SPACE_REPLACEMENT = '_SPACE_'; diff --git a/client/src/shared/types.ts b/client/src/shared/types.ts index 3d6e2e6848..736ae945f4 100644 --- a/client/src/shared/types.ts +++ b/client/src/shared/types.ts @@ -69,19 +69,18 @@ export type ComponentType = { // eslint-disable-next-line @typescript-eslint/no-explicit-any [key: string]: boolean; }; + label?: string; metadata?: { ui?: { condition?: string; dynamicPropertyTypes?: {[key: string]: string}; }; }; - notes?: string; operationName?: string; parameters?: { // eslint-disable-next-line @typescript-eslint/no-explicit-any [key: string]: any; }; - title?: string; type?: string; workflowNodeName: string; }; @@ -151,7 +150,7 @@ export type NodeType = { trigger?: boolean; type: string; version: number; - workflowNodeName?: string; + workflowNodeName: string; }; export type SubPropertyType = PropertyAllType & {custom: boolean};