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
## After
---
.../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 (
+
+ );
+};