From 5b1cfa4cc0d7f35407df5e5a6f146f40fcdeb084 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rapha=C3=ABl=20Bosi?=
<71827178+bosiraphael@users.noreply.github.com>
Date: Tue, 16 Jun 2026 16:30:23 +0200
Subject: [PATCH] Show app name on workflow logic function nodes (#21675)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Workflow logic-function nodes from installed integration apps now show
the owning app's name as the node label (e.g. "People Data Labs")
instead of the generic "Action". The descriptive title below it (e.g.
"Enrich Person") is unchanged.
This only applies to installed integration apps — plain custom-code
functions and standard functions keep showing "Action".
A new `useWorkflowNodeLabel` hook resolves the logic function's
`applicationId` and returns the app name for integration apps, falling
back to the node type otherwise. It's used by the editable, read-only,
and run node renderers.
## Before
## After
---
...WorkflowDiagramStepNodeEditableContent.tsx | 7 +++--
.../WorkflowDiagramStepNodeReadonly.tsx | 7 +++--
.../components/WorkflowRunDiagramStepNode.tsx | 7 +++--
.../hooks/useWorkflowNodeLabel.ts | 31 +++++++++++++++++++
4 files changed, 46 insertions(+), 6 deletions(-)
create mode 100644 packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/hooks/useWorkflowNodeLabel.ts
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeEditableContent.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeEditableContent.tsx
index 8c1a063fcf..2c651cae1c 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeEditableContent.tsx
+++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeEditableContent.tsx
@@ -17,13 +17,14 @@ import { WorkflowNodeRightPart } from '@/workflow/workflow-diagram/workflow-node
import { WorkflowNodeTitle } from '@/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeTitle';
import { WORKFLOW_DIAGRAM_NODE_DEFAULT_SOURCE_HANDLE_ID } from '@/workflow/workflow-diagram/workflow-nodes/constants/WorkflowDiagramNodeDefaultSourceHandleId';
import { useConnectionState } from '@/workflow/workflow-diagram/workflow-nodes/hooks/useConnectionState';
+import { useWorkflowNodeLabel } from '@/workflow/workflow-diagram/workflow-nodes/hooks/useWorkflowNodeLabel';
import { isNodeTitleHighlighted } from '@/workflow/workflow-diagram/workflow-nodes/utils/isNodeTitleHighlighted';
import { workflowInsertStepIdsComponentState } from '@/workflow/workflow-steps/states/workflowInsertStepIdsComponentState';
import { styled } from '@linaria/react';
import { useLingui } from '@lingui/react/macro';
import { Position } from '@xyflow/react';
import { useState } from 'react';
-import { capitalize, isDefined } from 'twenty-shared/utils';
+import { isDefined } from 'twenty-shared/utils';
const StyledAddStepButtonContainer = styled.div<{
shouldDisplay: boolean;
@@ -75,6 +76,8 @@ export const WorkflowDiagramStepNodeEditableContent = ({
const isNodeConnectable = isConnectable({ nodeId: id });
+ const nodeLabel = useWorkflowNodeLabel(data);
+
const handleAddStepButtonContainerClick = (
event: React.MouseEvent,
) => {
@@ -110,7 +113,7 @@ export const WorkflowDiagramStepNodeEditableContent = ({
- {capitalize(data.nodeType)}
+ {nodeLabel}
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeReadonly.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeReadonly.tsx
index fe50895f7f..8e4b6ff67e 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeReadonly.tsx
+++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowDiagramStepNodeReadonly.tsx
@@ -20,10 +20,11 @@ import { WorkflowNodeLabelWithCounterPart } from '@/workflow/workflow-diagram/wo
import { WorkflowNodeRightPart } from '@/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeRightPart';
import { WorkflowNodeTitle } from '@/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeTitle';
import { WORKFLOW_DIAGRAM_NODE_DEFAULT_SOURCE_HANDLE_ID } from '@/workflow/workflow-diagram/workflow-nodes/constants/WorkflowDiagramNodeDefaultSourceHandleId';
+import { useWorkflowNodeLabel } from '@/workflow/workflow-diagram/workflow-nodes/hooks/useWorkflowNodeLabel';
import { isNodeTitleHighlighted } from '@/workflow/workflow-diagram/workflow-nodes/utils/isNodeTitleHighlighted';
import { Position } from '@xyflow/react';
import { useContext } from 'react';
-import { capitalize, isDefined } from 'twenty-shared/utils';
+import { isDefined } from 'twenty-shared/utils';
import { useIcons } from 'twenty-ui-deprecated/display';
export const WorkflowDiagramStepNodeReadonly = ({
@@ -85,6 +86,8 @@ export const WorkflowDiagramStepNodeReadonly = ({
actionType: data.nodeType === 'action' ? data.actionType : undefined,
});
+ const nodeLabel = useWorkflowNodeLabel(data);
+
return (
<>
- {capitalize(data.nodeType)}
+ {nodeLabel}
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowRunDiagramStepNode.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowRunDiagramStepNode.tsx
index 318683a3ec..5e3d31594c 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowRunDiagramStepNode.tsx
+++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/components/WorkflowRunDiagramStepNode.tsx
@@ -22,11 +22,12 @@ import { WorkflowNodeLabel } from '@/workflow/workflow-diagram/workflow-nodes/co
import { WorkflowNodeRightPart } from '@/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeRightPart';
import { WorkflowNodeTitle } from '@/workflow/workflow-diagram/workflow-nodes/components/WorkflowNodeTitle';
import { WORKFLOW_DIAGRAM_NODE_DEFAULT_SOURCE_HANDLE_ID } from '@/workflow/workflow-diagram/workflow-nodes/constants/WorkflowDiagramNodeDefaultSourceHandleId';
+import { useWorkflowNodeLabel } from '@/workflow/workflow-diagram/workflow-nodes/hooks/useWorkflowNodeLabel';
import { getNodeIterationCount } from '@/workflow/workflow-diagram/workflow-nodes/utils/getNodeIterationCount';
import { styled } from '@linaria/react';
import { Position } from '@xyflow/react';
import { useContext } from 'react';
-import { capitalize, isDefined } from 'twenty-shared/utils';
+import { isDefined } from 'twenty-shared/utils';
import { StepStatus } from 'twenty-shared/workflow';
import { IconCheck, IconX, useIcons } from 'twenty-ui-deprecated/display';
import { Loader } from 'twenty-ui-deprecated/feedback';
@@ -116,6 +117,8 @@ export const WorkflowRunDiagramStepNode = ({
? getNodeIterationCount({ stepInfo })
: 0;
+ const nodeLabel = useWorkflowNodeLabel(data);
+
const handleClick = () => {
if (!isDefined(workflowVisualizerWorkflowId)) {
throw new Error('Workflow ID must be defined');
@@ -153,7 +156,7 @@ export const WorkflowRunDiagramStepNode = ({
- {capitalize(data.nodeType)}
+ {nodeLabel}
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/hooks/useWorkflowNodeLabel.ts b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/hooks/useWorkflowNodeLabel.ts
new file mode 100644
index 0000000000..1070ee1880
--- /dev/null
+++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/workflow-nodes/hooks/useWorkflowNodeLabel.ts
@@ -0,0 +1,31 @@
+import { useApplicationChipData } from '@/applications/hooks/useApplicationChipData';
+import { useIsThirdPartyApplication } from '@/applications/hooks/useIsThirdPartyApplication';
+import { logicFunctionsSelector } from '@/logic-functions/states/logicFunctionsSelector';
+import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
+import { type WorkflowDiagramStepNodeData } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
+import { capitalize, isDefined } from 'twenty-shared/utils';
+
+export const useWorkflowNodeLabel = (
+ data: WorkflowDiagramStepNodeData,
+): string => {
+ const logicFunctions = useAtomStateValue(logicFunctionsSelector);
+
+ const logicFunctionId =
+ data.nodeType === 'action' ? data.logicFunctionId : undefined;
+
+ const applicationId = isDefined(logicFunctionId)
+ ? logicFunctions.find(
+ (logicFunction) => logicFunction.id === logicFunctionId,
+ )?.applicationId
+ : undefined;
+
+ const isThirdPartyApplication = useIsThirdPartyApplication(applicationId);
+
+ const { applicationChipData } = useApplicationChipData({ applicationId });
+
+ if (isThirdPartyApplication) {
+ return applicationChipData.name;
+ }
+
+ return capitalize(data.nodeType);
+};