diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/action/components/CommandMenuWorkflowSelectActionContent.tsx b/packages/twenty-front/src/modules/command-menu/pages/workflow/action/components/CommandMenuWorkflowSelectActionContent.tsx
index a51f89997a..b355721b73 100644
--- a/packages/twenty-front/src/modules/command-menu/pages/workflow/action/components/CommandMenuWorkflowSelectActionContent.tsx
+++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/action/components/CommandMenuWorkflowSelectActionContent.tsx
@@ -1,4 +1,5 @@
import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu';
+import { WorkflowActionMenuItems } from '@/command-menu/pages/workflow/action/components/WorkflowActionMenuItems';
import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
@@ -12,13 +13,18 @@ import { RightDrawerStepListContainer } from '@/workflow/workflow-steps/componen
import { RightDrawerWorkflowSelectStepTitle } from '@/workflow/workflow-steps/components/RightDrawerWorkflowSelectStepTitle';
import { useCreateStep } from '@/workflow/workflow-steps/hooks/useCreateStep';
import { workflowInsertStepIdsComponentState } from '@/workflow/workflow-steps/states/workflowInsertStepIdsComponentState';
+import { AI_ACTIONS } from '@/workflow/workflow-steps/workflow-actions/constants/AiActions';
+import { CORE_ACTIONS } from '@/workflow/workflow-steps/workflow-actions/constants/CoreActions';
+import { HUMAN_INPUT_ACTIONS } from '@/workflow/workflow-steps/workflow-actions/constants/HumanInputActions';
import { RECORD_ACTIONS } from '@/workflow/workflow-steps/workflow-actions/constants/RecordActions';
-import { useFilteredOtherActions } from '@/workflow/workflow-steps/workflow-actions/hooks/useFilteredOtherActions';
import { getActionIcon } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIcon';
+import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
+import { useTheme } from '@emotion/react';
+import { useLingui } from '@lingui/react/macro';
import { useSetRecoilState } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
import { useIcons } from 'twenty-ui/display';
-import { MenuItemCommand } from 'twenty-ui/navigation';
+import { FeatureFlagKey } from '~/generated/graphql';
export const CommandMenuWorkflowSelectActionContent = ({
workflow,
@@ -30,7 +36,6 @@ export const CommandMenuWorkflowSelectActionContent = ({
const { createStep } = useCreateStep({
workflow,
});
- const filteredOtherActions = useFilteredOtherActions();
const { closeRightClickMenu } = useCloseRightClickMenu();
@@ -83,30 +88,34 @@ export const CommandMenuWorkflowSelectActionContent = ({
);
};
+ const theme = useTheme();
+
+ const isAiEnabled = useIsFeatureEnabled(FeatureFlagKey.IS_AI_ENABLED);
+
+ const { t } = useLingui();
+
return (
- Records
+ {t`Data`}
- {RECORD_ACTIONS.map((action) => (
- handleCreateStep(action.type)}
- />
- ))}
+ {WorkflowActionMenuItems(RECORD_ACTIONS, theme, handleCreateStep)}
+ {isAiEnabled && (
+ <>
+
+ {t`AI`}
+
+ {WorkflowActionMenuItems(AI_ACTIONS, theme, handleCreateStep)}
+ >
+ )}
- Other
+ {t`Core`}
- {filteredOtherActions.map((action) => (
- handleCreateStep(action.type)}
- />
- ))}
+ {WorkflowActionMenuItems(CORE_ACTIONS, theme, handleCreateStep)}
+
+ {t`Human Input`}
+
+ {WorkflowActionMenuItems(HUMAN_INPUT_ACTIONS, theme, handleCreateStep)}
);
};
diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/action/components/WorkflowActionMenuItems.tsx b/packages/twenty-front/src/modules/command-menu/pages/workflow/action/components/WorkflowActionMenuItems.tsx
new file mode 100644
index 0000000000..ea006188f8
--- /dev/null
+++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/action/components/WorkflowActionMenuItems.tsx
@@ -0,0 +1,32 @@
+import { type WorkflowActionType } from '@/workflow/types/Workflow';
+import { getActionIconColorOrThrow } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIconColorOrThrow';
+import { useIcons } from 'twenty-ui/display';
+import { MenuItemCommand } from 'twenty-ui/navigation';
+
+type Action = { type: WorkflowActionType; label: string; icon: string };
+
+export const WorkflowActionMenuItems = (
+ actions: Action[],
+ theme: any,
+ onClick: (actionType: WorkflowActionType) => void,
+) => {
+ const { getIcon } = useIcons();
+ return actions.map((action) => {
+ const Icon = getIcon(action.icon);
+ return (
+ (
+
+ )}
+ text={action.label}
+ onClick={() => onClick(action.type)}
+ />
+ );
+ });
+};
diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/trigger-type/components/CommandMenuWorkflowSelectTriggerTypeContent.tsx b/packages/twenty-front/src/modules/command-menu/pages/workflow/trigger-type/components/CommandMenuWorkflowSelectTriggerTypeContent.tsx
index 7c405bfb59..182d9657bb 100644
--- a/packages/twenty-front/src/modules/command-menu/pages/workflow/trigger-type/components/CommandMenuWorkflowSelectTriggerTypeContent.tsx
+++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/trigger-type/components/CommandMenuWorkflowSelectTriggerTypeContent.tsx
@@ -13,6 +13,7 @@ import { OTHER_TRIGGER_TYPES } from '@/workflow/workflow-trigger/constants/Other
import { useUpdateWorkflowVersionTrigger } from '@/workflow/workflow-trigger/hooks/useUpdateWorkflowVersionTrigger';
import { getTriggerDefaultDefinition } from '@/workflow/workflow-trigger/utils/getTriggerDefaultDefinition';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
+import { useTheme } from '@emotion/react';
import { TRIGGER_STEP_ID } from 'twenty-shared/workflow';
import { useIcons } from 'twenty-ui/display';
import { MenuItemCommand } from 'twenty-ui/navigation';
@@ -67,30 +68,39 @@ export const CommandMenuWorkflowSelectTriggerTypeContent = ({
};
};
+ const theme = useTheme();
+
return (
Data
- {DATABASE_TRIGGER_TYPES.map((action) => (
-
- ))}
+ {DATABASE_TRIGGER_TYPES.map((action) => {
+ const Icon = getIcon(action.icon);
+ return (
+ }
+ text={action.defaultLabel}
+ onClick={handleTriggerTypeClick(action)}
+ />
+ );
+ })}
+
Others
- {OTHER_TRIGGER_TYPES.map((action) => (
-
- ))}
+ {OTHER_TRIGGER_TYPES.map((action) => {
+ const Icon = getIcon(action.icon);
+ return (
+ }
+ text={action.defaultLabel}
+ onClick={handleTriggerTypeClick(action)}
+ />
+ );
+ })}
);
};
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 e59ce72c13..11314a4313 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
@@ -16,13 +16,13 @@ export const WorkflowDiagramStepNodeIcon = ({
switch (data.nodeType) {
case 'trigger': {
switch (data.triggerType) {
- case 'DATABASE_EVENT':
+ case 'DATABASE_EVENT': {
+ return ;
+ }
case 'MANUAL':
case 'CRON':
case 'WEBHOOK': {
- return (
-
- );
+ return ;
}
}
@@ -31,25 +31,26 @@ export const WorkflowDiagramStepNodeIcon = ({
case 'action': {
switch (data.actionType) {
case 'CODE':
- case 'HTTP_REQUEST': {
+ case 'HTTP_REQUEST':
+ case 'SEND_EMAIL': {
return (
);
}
- case 'SEND_EMAIL': {
- return ;
+ case 'FORM': {
+ return ;
}
case 'AI_AGENT': {
- return ;
+ return ;
}
default: {
return (
diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowRunStepOutputDetail.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowRunStepOutputDetail.tsx
index ccc7f4c970..b1d555acca 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowRunStepOutputDetail.tsx
+++ b/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowRunStepOutputDetail.tsx
@@ -56,7 +56,10 @@ export const WorkflowRunStepOutputDetail = ({ stepId }: { stepId: string }) => {
: getActionIcon(stepDefinition.definition.type);
const headerIconColor =
stepDefinition.type === 'trigger'
- ? getTriggerIconColor({ theme })
+ ? getTriggerIconColor({
+ theme,
+ triggerType: stepDefinition.definition.type,
+ })
: getActionIconColorOrThrow({
theme,
actionType: stepDefinition.definition.type,
diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/constants/AiActions.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/constants/AiActions.ts
new file mode 100644
index 0000000000..537c66fee6
--- /dev/null
+++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/constants/AiActions.ts
@@ -0,0 +1,13 @@
+import { type WorkflowActionType } from '@/workflow/types/Workflow';
+
+export const AI_ACTIONS: Array<{
+ label: string;
+ type: Extract;
+ icon: string;
+}> = [
+ {
+ label: 'AI Agent',
+ type: 'AI_AGENT',
+ icon: 'IconBrain',
+ },
+];
diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/constants/CoreActions.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/constants/CoreActions.ts
new file mode 100644
index 0000000000..e7179f89e1
--- /dev/null
+++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/constants/CoreActions.ts
@@ -0,0 +1,23 @@
+import { type WorkflowActionType } from '@/workflow/types/Workflow';
+
+export const CORE_ACTIONS: Array<{
+ label: string;
+ type: Extract;
+ icon: string;
+}> = [
+ {
+ label: 'Send Email',
+ type: 'SEND_EMAIL',
+ icon: 'IconSend',
+ },
+ {
+ label: 'Code',
+ type: 'CODE',
+ icon: 'IconCode',
+ },
+ {
+ label: 'HTTP Request',
+ type: 'HTTP_REQUEST',
+ icon: 'IconWorld',
+ },
+];
diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/constants/HumanInputActions.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/constants/HumanInputActions.ts
new file mode 100644
index 0000000000..ca7cc7722e
--- /dev/null
+++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/constants/HumanInputActions.ts
@@ -0,0 +1,13 @@
+import { type WorkflowActionType } from '@/workflow/types/Workflow';
+
+export const HUMAN_INPUT_ACTIONS: Array<{
+ label: string;
+ type: Extract;
+ icon: string;
+}> = [
+ {
+ label: 'Form',
+ type: 'FORM',
+ icon: 'IconForms',
+ },
+];
diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/hooks/__tests__/useFilteredOtherActions.test.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/hooks/__tests__/useFilteredOtherActions.test.ts
deleted file mode 100644
index e70d284ee1..0000000000
--- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/hooks/__tests__/useFilteredOtherActions.test.ts
+++ /dev/null
@@ -1,111 +0,0 @@
-import { renderHook } from '@testing-library/react';
-import { useFilteredOtherActions } from '../useFilteredOtherActions';
-
-jest.mock('@/workspace/hooks/useIsFeatureEnabled', () => ({
- useIsFeatureEnabled: jest.fn(),
-}));
-
-jest.mock('../../constants/OtherActions', () => ({
- OTHER_ACTIONS: [
- { type: 'CODE', icon: 'IconCode', label: 'Code' },
- { type: 'HTTP_REQUEST', icon: 'IconHttp', label: 'HTTP Request' },
- { type: 'SEND_EMAIL', icon: 'IconMail', label: 'Send Email' },
- { type: 'AI_AGENT', icon: 'IconBrain', label: 'AI Agent' },
- { type: 'FORM', icon: 'IconForm', label: 'Form' },
- ],
-}));
-
-describe('useFilteredOtherActions', () => {
- const mockUseIsFeatureEnabled = jest.mocked(
- jest.requireMock('@/workspace/hooks/useIsFeatureEnabled')
- .useIsFeatureEnabled,
- );
-
- beforeEach(() => {
- jest.clearAllMocks();
- });
-
- it('should return all actions when AI is enabled', () => {
- mockUseIsFeatureEnabled.mockReturnValue(true);
-
- const { result } = renderHook(() => useFilteredOtherActions());
-
- expect(result.current).toHaveLength(5);
- expect(result.current).toEqual([
- { type: 'CODE', icon: 'IconCode', label: 'Code' },
- { type: 'HTTP_REQUEST', icon: 'IconHttp', label: 'HTTP Request' },
- { type: 'SEND_EMAIL', icon: 'IconMail', label: 'Send Email' },
- { type: 'AI_AGENT', icon: 'IconBrain', label: 'AI Agent' },
- { type: 'FORM', icon: 'IconForm', label: 'Form' },
- ]);
- });
-
- it('should filter out AI_AGENT when AI is disabled', () => {
- mockUseIsFeatureEnabled.mockReturnValue(false);
-
- const { result } = renderHook(() => useFilteredOtherActions());
-
- expect(result.current).toHaveLength(4);
- expect(result.current).toEqual([
- { type: 'CODE', icon: 'IconCode', label: 'Code' },
- { type: 'HTTP_REQUEST', icon: 'IconHttp', label: 'HTTP Request' },
- { type: 'SEND_EMAIL', icon: 'IconMail', label: 'Send Email' },
- { type: 'FORM', icon: 'IconForm', label: 'Form' },
- ]);
- expect(
- result.current.find((action) => action.type === 'AI_AGENT'),
- ).toBeUndefined();
- });
-
- it('should call useIsFeatureEnabled with correct feature flag', () => {
- mockUseIsFeatureEnabled.mockReturnValue(true);
-
- renderHook(() => useFilteredOtherActions());
-
- expect(mockUseIsFeatureEnabled).toHaveBeenCalledWith('IS_AI_ENABLED');
- expect(mockUseIsFeatureEnabled).toHaveBeenCalledTimes(1);
- });
-
- it('should handle feature flag hook returning undefined', () => {
- mockUseIsFeatureEnabled.mockReturnValue(undefined);
-
- const { result } = renderHook(() => useFilteredOtherActions());
-
- expect(result.current).toHaveLength(4);
- expect(
- result.current.find((action) => action.type === 'AI_AGENT'),
- ).toBeUndefined();
- });
-
- it('should handle feature flag hook returning null', () => {
- mockUseIsFeatureEnabled.mockReturnValue(null);
-
- const { result } = renderHook(() => useFilteredOtherActions());
-
- expect(result.current).toHaveLength(4);
- expect(
- result.current.find((action) => action.type === 'AI_AGENT'),
- ).toBeUndefined();
- });
-
- it('should handle feature flag hook returning false string', () => {
- mockUseIsFeatureEnabled.mockReturnValue('false');
-
- const { result } = renderHook(() => useFilteredOtherActions());
-
- expect(result.current).toHaveLength(5);
- expect(
- result.current.find((action) => action.type === 'AI_AGENT'),
- ).toBeDefined();
- });
-
- it('should handle feature flag hook throwing error', () => {
- mockUseIsFeatureEnabled.mockImplementation(() => {
- throw new Error('Feature flag error');
- });
-
- expect(() => {
- renderHook(() => useFilteredOtherActions());
- }).toThrow('Feature flag error');
- });
-});
diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/hooks/useFilteredOtherActions.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/hooks/useFilteredOtherActions.ts
deleted file mode 100644
index 347507f1e6..0000000000
--- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/hooks/useFilteredOtherActions.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
-import { FeatureFlagKey } from '~/generated/graphql';
-import { OTHER_ACTIONS } from '../constants/OtherActions';
-
-export const useFilteredOtherActions = () => {
- const isAiEnabled = useIsFeatureEnabled(FeatureFlagKey.IS_AI_ENABLED);
-
- return OTHER_ACTIONS.filter((action) => {
- return action.type !== 'AI_AGENT' || isAiEnabled;
- });
-};
diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/utils/__tests__/getActionIcon.test.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/utils/__tests__/getActionIcon.test.ts
index 7794a03ba0..e087a5daf8 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/utils/__tests__/getActionIcon.test.ts
+++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/utils/__tests__/getActionIcon.test.ts
@@ -1,4 +1,6 @@
-import { OTHER_ACTIONS } from '../../constants/OtherActions';
+import { AI_ACTIONS } from '../../constants/AiActions';
+import { CORE_ACTIONS } from '../../constants/CoreActions';
+import { HUMAN_INPUT_ACTIONS } from '../../constants/HumanInputActions';
import { RECORD_ACTIONS } from '../../constants/RecordActions';
import { getActionIcon } from '../getActionIcon';
@@ -8,13 +10,21 @@ describe('getActionIcon', () => {
expect(getActionIcon(action.type)).toBe(action.icon);
});
- OTHER_ACTIONS.forEach((action) => {
+ AI_ACTIONS.forEach((action) => {
+ expect(getActionIcon(action.type)).toBe(action.icon);
+ });
+
+ CORE_ACTIONS.forEach((action) => {
+ expect(getActionIcon(action.type)).toBe(action.icon);
+ });
+
+ HUMAN_INPUT_ACTIONS.forEach((action) => {
expect(getActionIcon(action.type)).toBe(action.icon);
});
});
- it('should return undefined for unknown action type', () => {
+ it('should return IconDefault for unknown action type', () => {
// @ts-expect-error Testing invalid action type
- expect(getActionIcon('UNKNOWN_ACTION')).toBeUndefined();
+ expect(getActionIcon('UNKNOWN_ACTION')).toBe('IconDefault');
});
});
diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/utils/__tests__/getActionIconColorOrThrow.test.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/utils/__tests__/getActionIconColorOrThrow.test.ts
index 38e8a60976..5b1bcd617a 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/utils/__tests__/getActionIconColorOrThrow.test.ts
+++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/utils/__tests__/getActionIconColorOrThrow.test.ts
@@ -6,8 +6,8 @@ import { getActionIconColorOrThrow } from '../getActionIconColorOrThrow';
const mockTheme: Theme = {
color: {
orange: COLOR.orange,
- blue: COLOR.blue,
pink: COLOR.pink,
+ red: COLOR.red,
},
font: {
color: {
@@ -17,10 +17,23 @@ const mockTheme: Theme = {
} as Theme;
describe('getActionIconColorOrThrow', () => {
- it('should return orange color for CODE action type', () => {
- expect(
- getActionIconColorOrThrow({ theme: mockTheme, actionType: 'CODE' }),
- ).toBe(mockTheme.color.orange);
+ describe('action types that return red color', () => {
+ const coreActionTypes: WorkflowActionType[] = [
+ 'CODE',
+ 'HTTP_REQUEST',
+ 'SEND_EMAIL',
+ ];
+
+ coreActionTypes.forEach((actionType) => {
+ it(`should return red color for ${actionType} action type`, () => {
+ const result = getActionIconColorOrThrow({
+ theme: mockTheme,
+ actionType,
+ });
+
+ expect(result).toBe(mockTheme.color.red);
+ });
+ });
});
describe('action types that return tertiary font color', () => {
@@ -29,7 +42,6 @@ describe('getActionIconColorOrThrow', () => {
'UPDATE_RECORD',
'DELETE_RECORD',
'FIND_RECORDS',
- 'FORM',
];
recordActionTypes.forEach((actionType) => {
@@ -44,14 +56,14 @@ describe('getActionIconColorOrThrow', () => {
});
});
- describe('action types that return blue color', () => {
- it('should return blue color for SEND_EMAIL action type', () => {
+ describe('action types that return orange color', () => {
+ it('should return orange color for FORM action type', () => {
const result = getActionIconColorOrThrow({
theme: mockTheme,
- actionType: 'SEND_EMAIL',
+ actionType: 'FORM',
});
- expect(result).toBe(mockTheme.color.blue);
+ expect(result).toBe(mockTheme.color.orange);
});
});
@@ -81,8 +93,8 @@ describe('getActionIconColorOrThrow', () => {
it('should use the provided theme colors correctly', () => {
const customTheme: Theme = {
color: {
- orange: COLOR.red,
- blue: COLOR.purple,
+ red: COLOR.red,
+ orange: COLOR.orange,
pink: COLOR.turquoise,
},
font: {
@@ -104,7 +116,7 @@ describe('getActionIconColorOrThrow', () => {
theme: customTheme,
actionType: 'SEND_EMAIL',
}),
- ).toBe(COLOR.purple);
+ ).toBe(COLOR.red);
expect(
getActionIconColorOrThrow({
@@ -158,12 +170,12 @@ describe('getActionIconColorOrThrow', () => {
});
expect(result1).toBe(result2);
- expect(result1).toBe(mockTheme.color.orange);
+ expect(result1).toBe(mockTheme.color.red);
});
});
describe('color grouping logic', () => {
- it('should group CODE and HTTP_REQUEST actions with orange color', () => {
+ it('should group CODE and HTTP_REQUEST actions with red color', () => {
const orangeActions: WorkflowActionType[] = ['CODE', 'HTTP_REQUEST'];
orangeActions.forEach((actionType) => {
@@ -171,7 +183,7 @@ describe('getActionIconColorOrThrow', () => {
theme: mockTheme,
actionType,
});
- expect(result).toBe(mockTheme.color.orange);
+ expect(result).toBe(mockTheme.color.red);
});
});
@@ -181,7 +193,6 @@ describe('getActionIconColorOrThrow', () => {
'UPDATE_RECORD',
'DELETE_RECORD',
'FIND_RECORDS',
- 'FORM',
];
recordActions.forEach((actionType) => {
@@ -202,13 +213,13 @@ describe('getActionIconColorOrThrow', () => {
expect(tertiaryResult).toBe(mockTheme.font.color.tertiary);
});
- it('should return blue color for SEND_EMAIL action type', () => {
+ it('should return red color for SEND_EMAIL action type', () => {
expect(
getActionIconColorOrThrow({
theme: mockTheme,
actionType: 'SEND_EMAIL',
}),
- ).toBe(mockTheme.color.blue);
+ ).toBe(mockTheme.color.red);
});
it('should return pink color for AI_AGENT action type', () => {
@@ -220,8 +231,8 @@ describe('getActionIconColorOrThrow', () => {
it('should use the provided theme colors correctly', () => {
const customTheme: Theme = {
color: {
- orange: COLOR.red,
- blue: COLOR.purple,
+ red: COLOR.red,
+ orange: COLOR.orange,
pink: COLOR.turquoise,
},
font: {
@@ -239,7 +250,7 @@ describe('getActionIconColorOrThrow', () => {
theme: customTheme,
actionType: 'SEND_EMAIL',
}),
- ).toBe(COLOR.purple);
+ ).toBe(COLOR.red);
expect(
getActionIconColorOrThrow({
theme: customTheme,
@@ -254,7 +265,7 @@ describe('getActionIconColorOrThrow', () => {
).toBe(GRAY_SCALE.gray50);
});
- it('should return undefined when blue color is missing for SEND_EMAIL action', () => {
+ it('should return undefined when red color is missing for SEND_EMAIL action', () => {
const themeWithoutBlue: Theme = {
color: {
orange: COLOR.orange,
diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/utils/getActionIcon.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/utils/getActionIcon.ts
index 23fee0554d..1da2091338 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/utils/getActionIcon.ts
+++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/utils/getActionIcon.ts
@@ -1,5 +1,7 @@
import { type WorkflowActionType } from '@/workflow/types/Workflow';
-import { OTHER_ACTIONS } from '@/workflow/workflow-steps/workflow-actions/constants/OtherActions';
+import { AI_ACTIONS } from '@/workflow/workflow-steps/workflow-actions/constants/AiActions';
+import { CORE_ACTIONS } from '@/workflow/workflow-steps/workflow-actions/constants/CoreActions';
+import { HUMAN_INPUT_ACTIONS } from '@/workflow/workflow-steps/workflow-actions/constants/HumanInputActions';
import { RECORD_ACTIONS } from '@/workflow/workflow-steps/workflow-actions/constants/RecordActions';
export const getActionIcon = (actionType: WorkflowActionType) => {
@@ -11,7 +13,15 @@ export const getActionIcon = (actionType: WorkflowActionType) => {
return RECORD_ACTIONS.find((item) => item.type === actionType)?.icon;
case 'FILTER':
return 'IconFilter';
+ case 'AI_AGENT':
+ return AI_ACTIONS.find((item) => item.type === actionType)?.icon;
+ case 'CODE':
+ case 'HTTP_REQUEST':
+ case 'SEND_EMAIL':
+ return CORE_ACTIONS.find((item) => item.type === actionType)?.icon;
+ case 'FORM':
+ return HUMAN_INPUT_ACTIONS.find((item) => item.type === actionType)?.icon;
default:
- return OTHER_ACTIONS.find((item) => item.type === actionType)?.icon;
+ return 'IconDefault';
}
};
diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/utils/getActionIconColorOrThrow.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/utils/getActionIconColorOrThrow.ts
index c0773c06ce..9adfb9eff8 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/utils/getActionIconColorOrThrow.ts
+++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/utils/getActionIconColorOrThrow.ts
@@ -12,16 +12,17 @@ export const getActionIconColorOrThrow = ({
switch (actionType) {
case 'CODE':
case 'HTTP_REQUEST':
- return theme.color.orange;
+ case 'SEND_EMAIL':
+ return theme.color.red;
case 'CREATE_RECORD':
case 'UPDATE_RECORD':
case 'DELETE_RECORD':
case 'FIND_RECORDS':
+ return theme.font.color.tertiary;
case 'FORM':
+ return theme.color.orange;
case 'FILTER':
return theme.font.color.tertiary;
- case 'SEND_EMAIL':
- return theme.color.blue;
case 'AI_AGENT':
return theme.color.pink;
default:
diff --git a/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerCronForm.tsx b/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerCronForm.tsx
index 075e35c1a3..a75ffaf402 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerCronForm.tsx
+++ b/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerCronForm.tsx
@@ -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}
diff --git a/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerDatabaseEventForm.tsx b/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerDatabaseEventForm.tsx
index 430b94c653..6e14786e71 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerDatabaseEventForm.tsx
+++ b/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerDatabaseEventForm.tsx
@@ -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}
diff --git a/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerManualForm.tsx b/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerManualForm.tsx
index 698fc867cc..7ba332eb32 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerManualForm.tsx
+++ b/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerManualForm.tsx
@@ -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}
diff --git a/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerWebhookForm.tsx b/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerWebhookForm.tsx
index 861094a68d..512b708f23 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerWebhookForm.tsx
+++ b/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerWebhookForm.tsx
@@ -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}
diff --git a/packages/twenty-front/src/modules/workflow/workflow-trigger/utils/__tests__/getTriggerIconColor.test.ts b/packages/twenty-front/src/modules/workflow/workflow-trigger/utils/__tests__/getTriggerIconColor.test.ts
index 9fe7085562..b9bb791c2a 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-trigger/utils/__tests__/getTriggerIconColor.test.ts
+++ b/packages/twenty-front/src/modules/workflow/workflow-trigger/utils/__tests__/getTriggerIconColor.test.ts
@@ -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);
});
});
diff --git a/packages/twenty-front/src/modules/workflow/workflow-trigger/utils/getTriggerIconColor.ts b/packages/twenty-front/src/modules/workflow/workflow-trigger/utils/getTriggerIconColor.ts
index 36c6df8897..eebbdf8f8a 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-trigger/utils/getTriggerIconColor.ts
+++ b/packages/twenty-front/src/modules/workflow/workflow-trigger/utils/getTriggerIconColor.ts
@@ -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;
+ }
};