fix: workflow node classification (#13945)

closes #13391 
As the solution said to classify workflow nodes based on colors I have
updated them with the following colors and new categories to better
classify and identify different node types as told:

  - Trigger Colors: Data (palette blue), Other (palette purple)
- Action Colors: Data (text/tertiary), AI (palette pink), Flow (tag
green), Human Input (palette orange)
 
<img width="451" height="690" alt="image"
src="https://github.com/user-attachments/assets/8c000f22-8f25-4b1d-ac6f-f2639b1eff94"
/>

<img width="451" height="690" alt="image"
src="https://github.com/user-attachments/assets/15a11a98-3fec-4374-a5f7-d7caf2ae5334"
/>

<img width="480" height="690" alt="image"
src="https://github.com/user-attachments/assets/6382f538-be6d-4595-b967-e7911f7ad61f"
/>

<img width="899" height="761" alt="image"
src="https://github.com/user-attachments/assets/98c97cd4-54cd-4bee-91b5-dd7cd3b03a5e"
/>

---------

Co-authored-by: Thomas Trompette <thomas.trompette@sfr.fr>
This commit is contained in:
P Harshith Rao
2025-08-20 15:01:03 +05:30
committed by GitHub
parent ae160e8b15
commit 521ef5ea4c
20 changed files with 279 additions and 239 deletions
@@ -10,6 +10,7 @@ import { getCronTriggerDefaultSettings } from '@/workflow/workflow-trigger/utils
import { getTriggerDefaultLabel } from '@/workflow/workflow-trigger/utils/getTriggerDefaultLabel';
import { getTriggerHeaderType } from '@/workflow/workflow-trigger/utils/getTriggerHeaderType';
import { getTriggerIcon } from '@/workflow/workflow-trigger/utils/getTriggerIcon';
import { getTriggerIconColor } from '@/workflow/workflow-trigger/utils/getTriggerIconColor';
import { useTheme } from '@emotion/react';
import { t } from '@lingui/core/macro';
import { isNumber } from '@sniptt/guards';
@@ -75,7 +76,7 @@ export const WorkflowEditTriggerCronForm = ({
});
}}
Icon={getIcon(headerIcon)}
iconColor={theme.font.color.tertiary}
iconColor={getTriggerIconColor({ theme, triggerType: trigger.type })}
initialTitle={headerTitle}
headerType={headerType}
disabled={triggerOptions.readonly}
@@ -18,6 +18,7 @@ import { WorkflowStepHeader } from '@/workflow/workflow-steps/components/Workflo
import { getTriggerDefaultLabel } from '@/workflow/workflow-trigger/utils/getTriggerDefaultLabel';
import { getTriggerHeaderType } from '@/workflow/workflow-trigger/utils/getTriggerHeaderType';
import { getTriggerIcon } from '@/workflow/workflow-trigger/utils/getTriggerIcon';
import { getTriggerIconColor } from '@/workflow/workflow-trigger/utils/getTriggerIconColor';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { Trans } from '@lingui/react/macro';
@@ -181,7 +182,7 @@ export const WorkflowEditTriggerDatabaseEventForm = ({
});
}}
Icon={getIcon(headerIcon)}
iconColor={theme.font.color.tertiary}
iconColor={getTriggerIconColor({ theme, triggerType: trigger.type })}
initialTitle={defaultLabel}
headerType={headerType}
disabled={triggerOptions.readonly}
@@ -15,6 +15,7 @@ import { getManualTriggerDefaultSettings } from '@/workflow/workflow-trigger/uti
import { getTriggerDefaultLabel } from '@/workflow/workflow-trigger/utils/getTriggerDefaultLabel';
import { getTriggerHeaderType } from '@/workflow/workflow-trigger/utils/getTriggerHeaderType';
import { getTriggerIcon } from '@/workflow/workflow-trigger/utils/getTriggerIcon';
import { getTriggerIconColor } from '@/workflow/workflow-trigger/utils/getTriggerIconColor';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { useLingui } from '@lingui/react/macro';
@@ -103,7 +104,7 @@ export const WorkflowEditTriggerManualForm = ({
});
}}
Icon={getIcon(headerIcon)}
iconColor={theme.font.color.tertiary}
iconColor={getTriggerIconColor({ theme, triggerType: trigger.type })}
initialTitle={headerTitle}
headerType={headerType}
disabled={triggerOptions.readonly}
@@ -15,6 +15,7 @@ import { WEBHOOK_TRIGGER_HTTP_METHOD_OPTIONS } from '@/workflow/workflow-trigger
import { getTriggerDefaultLabel } from '@/workflow/workflow-trigger/utils/getTriggerDefaultLabel';
import { getTriggerHeaderType } from '@/workflow/workflow-trigger/utils/getTriggerHeaderType';
import { getTriggerIcon } from '@/workflow/workflow-trigger/utils/getTriggerIcon';
import { getTriggerIconColor } from '@/workflow/workflow-trigger/utils/getTriggerIconColor';
import { getWebhookTriggerDefaultSettings } from '@/workflow/workflow-trigger/utils/getWebhookTriggerDefaultSettings';
import { useTheme } from '@emotion/react';
import { isNonEmptyString } from '@sniptt/guards';
@@ -95,7 +96,7 @@ export const WorkflowEditTriggerWebhookForm = ({
});
}}
Icon={getIcon(headerIcon)}
iconColor={theme.font.color.tertiary}
iconColor={getTriggerIconColor({ theme, triggerType: trigger.type })}
initialTitle={headerTitle}
headerType={headerType}
disabled={triggerOptions.readonly}
@@ -1,56 +1,62 @@
/* eslint-disable @nx/workspace-no-hardcoded-colors */
import { type Theme } from '@emotion/react';
import { COLOR } from 'twenty-ui/theme';
import { getTriggerIconColor } from '../getTriggerIconColor';
describe('getTriggerIconColor', () => {
const mockTheme: Theme = {
font: {
color: {
primary: '#2c2c2c',
secondary: '#666666',
tertiary: '#999999',
light: '#cccccc',
},
color: {
blue: COLOR.blue,
purple: COLOR.purple,
},
} as unknown as Theme;
it('returns the tertiary font color from theme', () => {
const result = getTriggerIconColor({ theme: mockTheme });
it('returns the blue color for database event from theme', () => {
const result = getTriggerIconColor({
theme: mockTheme,
triggerType: 'DATABASE_EVENT',
});
expect(result).toBe('#999999');
expect(result).toBe(COLOR.blue);
});
it('returns the purple color for cron from theme', () => {
const result = getTriggerIconColor({
theme: mockTheme,
triggerType: 'CRON',
});
expect(result).toBe(COLOR.purple);
});
it('works with different theme configurations', () => {
const differentTheme: Theme = {
font: {
color: {
primary: '#000000',
secondary: '#444444',
tertiary: '#888888',
light: '#ffffff',
},
color: {
blue: COLOR.blue,
purple: COLOR.purple,
},
} as unknown as Theme;
const result = getTriggerIconColor({ theme: differentTheme });
const result = getTriggerIconColor({
theme: differentTheme,
triggerType: 'DATABASE_EVENT',
});
expect(result).toBe('#888888');
expect(result).toBe(COLOR.blue);
});
it('maintains reference to theme.font.color.tertiary', () => {
it('maintains reference to theme.color.blue', () => {
const customTheme: Theme = {
font: {
color: {
primary: '#111111',
secondary: '#333333',
tertiary: '#custom-tertiary-color',
light: '#eeeeee',
},
color: {
blue: COLOR.blue,
purple: COLOR.purple,
},
} as unknown as Theme;
const result = getTriggerIconColor({ theme: customTheme });
const result = getTriggerIconColor({
theme: customTheme,
triggerType: 'DATABASE_EVENT',
});
expect(result).toBe('#custom-tertiary-color');
expect(result).toBe(COLOR.blue);
});
});
@@ -1,5 +1,21 @@
import { type Theme } from '@emotion/react';
import { type WorkflowTriggerType } from '@/workflow/types/Workflow';
export const getTriggerIconColor = ({ theme }: { theme: Theme }) => {
return theme.font.color.tertiary;
export const getTriggerIconColor = ({
theme,
triggerType,
}: {
theme: Theme;
triggerType: WorkflowTriggerType;
}) => {
switch (triggerType) {
case 'DATABASE_EVENT':
return theme.color.blue;
case 'CRON':
case 'MANUAL':
case 'WEBHOOK':
return theme.color.purple;
default:
return theme.color.purple;
}
};