From bd4161a90578f705afc5d24f41e9e090a4faeeb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Bosi?= <71827178+bosiraphael@users.noreply.github.com> Date: Fri, 12 Jun 2026 15:36:30 +0200 Subject: [PATCH] Show app logo on workflow logic function nodes (#21482) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Workflow `LOGIC_FUNCTION` action nodes (functions provided by an installed app) previously rendered a generic ƒ icon in the diagram. They now display the owning app's logo instead. The node's logic function id is resolved to its `applicationId` and rendered via the existing `AppChip`. When no app can be resolved (e.g. the logic function isn't loaded yet, or has no application), it falls back to the original ƒ icon, so nodes never look broken. Inline `CODE` actions are unchanged. ## Before CleanShot 2026-06-12 at 15 27 22@2x ## After CleanShot 2026-06-12 at 15 26 22@2x Review in cubic --- .../workflow-diagram/types/WorkflowDiagram.ts | 1 + .../generateNodesAndEdgesForDefaultNode.ts | 3 ++ .../WorkflowDiagramStepNodeIcon.tsx | 8 ++++ ...rkflowDiagramStepNodeLogicFunctionIcon.tsx | 38 +++++++++++++++++++ 4 files changed, 50 insertions(+) create mode 100644 packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeLogicFunctionIcon.tsx diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/types/WorkflowDiagram.ts b/packages/twenty-front/src/modules/workflow/workflow-diagram/types/WorkflowDiagram.ts index 6b71cd1935e..201054b4ff6 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/types/WorkflowDiagram.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/types/WorkflowDiagram.ts @@ -65,6 +65,7 @@ export type WorkflowDiagramStepNodeData = nodeType: 'action'; actionType: WorkflowActionType; name: string; + logicFunctionId?: string; runStatus?: WorkflowRunStepStatus; hasNextStepIds: boolean; stepId: string; diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/utils/generateNodesAndEdgesForDefaultNode.ts b/packages/twenty-front/src/modules/workflow/workflow-diagram/utils/generateNodesAndEdgesForDefaultNode.ts index eaa4709b1af..f87fbd06793 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/utils/generateNodesAndEdgesForDefaultNode.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/utils/generateNodesAndEdgesForDefaultNode.ts @@ -47,6 +47,9 @@ export const generateNodesAndEdgesForDefaultNode = ({ nodeType: 'action', actionType: step.type, name: step.name, + ...(step.type === 'LOGIC_FUNCTION' + ? { logicFunctionId: step.settings.input.logicFunctionId } + : {}), hasNextStepIds: isDefined(step.nextStepIds) && step.nextStepIds.length > 0, stepId: step.id, diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeIcon.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeIcon.tsx index 3f3e538d6da..4a19b81d288 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeIcon.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeIcon.tsx @@ -1,5 +1,6 @@ import { type WorkflowDiagramStepNodeData } from '@/workflow/workflow-diagram/types/WorkflowDiagram'; import { getWorkflowNodeIconKey } from '@/workflow/workflow-diagram/utils/getWorkflowNodeIconKey'; +import { WorkflowDiagramStepNodeLogicFunctionIcon } from '@/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeLogicFunctionIcon'; import { assertUnreachable } from 'twenty-shared/utils'; import { useIcons } from 'twenty-ui-deprecated/display'; import { ThemeContext } from 'twenty-ui-deprecated/theme-constants'; @@ -43,6 +44,13 @@ export const WorkflowDiagramStepNodeIcon = ({ /> ); } + case 'LOGIC_FUNCTION': { + return ( + + ); + } case 'FORM': { return ; } diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeLogicFunctionIcon.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeLogicFunctionIcon.tsx new file mode 100644 index 00000000000..7cb9ba221e9 --- /dev/null +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeLogicFunctionIcon.tsx @@ -0,0 +1,38 @@ +import { AppChip } from '@/applications/components/AppChip'; +import { logicFunctionsSelector } from '@/logic-functions/states/logicFunctionsSelector'; +import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; +import { getActionIcon } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIcon'; +import { useContext } from 'react'; +import { isDefined } from 'twenty-shared/utils'; +import { useIcons } from 'twenty-ui-deprecated/display'; +import { ThemeContext } from 'twenty-ui-deprecated/theme-constants'; + +export const WorkflowDiagramStepNodeLogicFunctionIcon = ({ + logicFunctionId, +}: { + logicFunctionId?: string; +}) => { + const { theme } = useContext(ThemeContext); + const { getIcon } = useIcons(); + const logicFunctions = useAtomStateValue(logicFunctionsSelector); + + const applicationId = isDefined(logicFunctionId) + ? logicFunctions.find( + (logicFunction) => logicFunction.id === logicFunctionId, + )?.applicationId + : undefined; + + if (isDefined(applicationId)) { + return ; + } + + const FallbackIcon = getIcon(getActionIcon('LOGIC_FUNCTION')); + + return ( + + ); +};