From efced12b4f67a1f95ae67e1a08f9ebdece3ce43c Mon Sep 17 00:00:00 2001 From: Dipak Halkude Date: Thu, 9 Oct 2025 19:42:34 +0530 Subject: [PATCH 1/2] feat: display specific action types in workflow side panel tooltips --- .../command-menu/components/SidePanelHeader.tsx | 12 ++++++++++-- .../utils/getActionHeaderTypeOrThrow.ts | 8 +++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/packages/twenty-front/src/modules/command-menu/components/SidePanelHeader.tsx b/packages/twenty-front/src/modules/command-menu/components/SidePanelHeader.tsx index 5772f2f5c2d28..f37ef506d5289 100644 --- a/packages/twenty-front/src/modules/command-menu/components/SidePanelHeader.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/SidePanelHeader.tsx @@ -3,7 +3,7 @@ import { TitleInput } from '@/ui/input/components/TitleInput'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { useState } from 'react'; -import { type IconComponent } from 'twenty-ui/display'; +import { AppTooltip, type IconComponent } from 'twenty-ui/display'; const StyledHeader = styled.div` background-color: ${({ theme }) => theme.background.secondary}; @@ -89,15 +89,23 @@ export const SidePanelHeader = ({ }); }; + // Create a unique ID for the tooltip anchor + const tooltipId = `side-panel-icon-tooltip-${headerType.replace(/\s+/g, '-')}`; + return ( - + + { case 'CODE': return msg`Code`; case 'CREATE_RECORD': + return msg`Create Record`; case 'UPDATE_RECORD': + return msg`Update Record`; case 'DELETE_RECORD': case 'UPSERT_RECORD': + return msg`Delete Record`; case 'FIND_RECORDS': + return msg`Find Records`; case 'FORM': + return msg`Form`; case 'SEND_EMAIL': + return msg`Send Email`; case 'DELAY': - return msg`Action`; + return msg`Delay`; case 'HTTP_REQUEST': return msg`HTTP Request`; case 'AI_AGENT': From b9f68f9fa2052ccf0c2033fd004eb8c0e0cec9f8 Mon Sep 17 00:00:00 2001 From: Thomas Trompette Date: Wed, 22 Oct 2025 11:32:34 +0200 Subject: [PATCH 2/2] Set const for default label + add a tooltip props --- .../components/SidePanelHeader.tsx | 15 +++-- .../components/WorkflowActionMenuItems.tsx | 8 ++- .../components/WorkflowEditActionAiAgent.tsx | 4 +- .../WorkflowEditActionServerlessFunction.tsx | 4 +- .../WorkflowEditActionCreateRecord.tsx | 4 +- .../WorkflowEditActionDeleteRecord.tsx | 4 +- .../WorkflowEditActionSendEmail.tsx | 4 +- .../WorkflowEditActionUpdateRecord.tsx | 4 +- .../WorkflowEditActionUpsertRecord.tsx | 4 +- .../workflow-actions/constants/AiActions.ts | 11 +--- .../workflow-actions/constants/CoreActions.ts | 23 ++------ .../workflow-actions/constants/FlowActions.ts | 23 ++------ .../constants/HumanInputActions.ts | 11 +--- .../constants/RecordActions.ts | 37 ++++-------- .../constants/actions/AiAgentAction.ts | 11 ++++ .../constants/actions/CodeAction.ts | 11 ++++ .../constants/actions/CreateRecordAction.ts | 11 ++++ .../constants/actions/DelayAction.ts | 11 ++++ .../constants/actions/DeleteRecordAction.ts | 11 ++++ .../constants/actions/FilterAction.ts | 11 ++++ .../constants/actions/FindRecordsAction.ts | 11 ++++ .../constants/actions/FormAction.ts | 11 ++++ .../constants/actions/HttpRequestAction.ts | 11 ++++ .../constants/actions/IteratorAction.ts | 11 ++++ .../constants/actions/SendEmailAction.ts | 11 ++++ .../constants/actions/UpdateRecordAction.ts | 11 ++++ .../constants/actions/UpsertRecordAction.ts | 11 ++++ .../components/WorkflowEditActionDelay.tsx | 4 +- .../components/WorkflowEditActionFilter.tsx | 4 +- .../WorkflowEditActionFindRecords.tsx | 4 +- .../WorkflowEditActionFormBuilder.tsx | 15 ++--- .../WorkflowEditActionFormFiller.tsx | 18 +++--- .../WorkflowEditActionHttpRequest.tsx | 4 +- .../components/WorkflowEditActionIterator.tsx | 4 +- .../getActionHeaderTypeOrThrow.test.ts | 29 ++++----- .../utils/getActionHeaderTypeOrThrow.ts | 59 ++++++++----------- .../WorkflowEditTriggerCronForm.tsx | 1 + .../WorkflowEditTriggerDatabaseEventForm.tsx | 1 + .../components/WorkflowEditTriggerManual.tsx | 1 + .../WorkflowEditTriggerWebhookForm.tsx | 1 + .../constants/DatabaseTriggerTypes.ts | 34 +++-------- .../constants/OtherTriggerTypes.ts | 21 ++----- .../constants/triggers/CronTrigger.ts | 11 ++++ .../constants/triggers/ManualTrigger.ts | 11 ++++ .../triggers/RecordIsCreatedTrigger.ts | 14 +++++ .../triggers/RecordIsDeletedTrigger.ts | 14 +++++ .../triggers/RecordIsUpdatedTrigger.ts | 14 +++++ .../triggers/RecordUpsertedTrigger.ts | 14 +++++ .../constants/triggers/WebhookTrigger.ts | 11 ++++ .../__tests__/getTriggerHeaderType.test.ts | 8 +-- .../utils/getTriggerHeaderType.ts | 2 +- 51 files changed, 388 insertions(+), 210 deletions(-) create mode 100644 packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/constants/actions/AiAgentAction.ts create mode 100644 packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/constants/actions/CodeAction.ts create mode 100644 packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/constants/actions/CreateRecordAction.ts create mode 100644 packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/constants/actions/DelayAction.ts create mode 100644 packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/constants/actions/DeleteRecordAction.ts create mode 100644 packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/constants/actions/FilterAction.ts create mode 100644 packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/constants/actions/FindRecordsAction.ts create mode 100644 packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/constants/actions/FormAction.ts create mode 100644 packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/constants/actions/HttpRequestAction.ts create mode 100644 packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/constants/actions/IteratorAction.ts create mode 100644 packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/constants/actions/SendEmailAction.ts create mode 100644 packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/constants/actions/UpdateRecordAction.ts create mode 100644 packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/constants/actions/UpsertRecordAction.ts create mode 100644 packages/twenty-front/src/modules/workflow/workflow-trigger/constants/triggers/CronTrigger.ts create mode 100644 packages/twenty-front/src/modules/workflow/workflow-trigger/constants/triggers/ManualTrigger.ts create mode 100644 packages/twenty-front/src/modules/workflow/workflow-trigger/constants/triggers/RecordIsCreatedTrigger.ts create mode 100644 packages/twenty-front/src/modules/workflow/workflow-trigger/constants/triggers/RecordIsDeletedTrigger.ts create mode 100644 packages/twenty-front/src/modules/workflow/workflow-trigger/constants/triggers/RecordIsUpdatedTrigger.ts create mode 100644 packages/twenty-front/src/modules/workflow/workflow-trigger/constants/triggers/RecordUpsertedTrigger.ts create mode 100644 packages/twenty-front/src/modules/workflow/workflow-trigger/constants/triggers/WebhookTrigger.ts diff --git a/packages/twenty-front/src/modules/command-menu/components/SidePanelHeader.tsx b/packages/twenty-front/src/modules/command-menu/components/SidePanelHeader.tsx index f37ef506d5289..b8c347c28555f 100644 --- a/packages/twenty-front/src/modules/command-menu/components/SidePanelHeader.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/SidePanelHeader.tsx @@ -52,6 +52,7 @@ type SidePanelHeaderProps = { iconColor: string; initialTitle: string; headerType: string; + iconTooltip?: string; } & ( | { disabled: true; @@ -70,6 +71,7 @@ export const SidePanelHeader = ({ headerType, disabled, onTitleChange, + iconTooltip, }: SidePanelHeaderProps) => { const theme = useTheme(); @@ -89,7 +91,6 @@ export const SidePanelHeader = ({ }); }; - // Create a unique ID for the tooltip anchor const tooltipId = `side-panel-icon-tooltip-${headerType.replace(/\s+/g, '-')}`; return ( @@ -101,11 +102,13 @@ export const SidePanelHeader = ({ size={theme.icon.size.lg} /> - + {iconTooltip && ( + + )} )} - text={action.label} + text={action.defaultLabel} onClick={() => onClick(action.type)} /> ); diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/ai-agent-action/components/WorkflowEditActionAiAgent.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/ai-agent-action/components/WorkflowEditActionAiAgent.tsx index 8adc346106fed..3ab3eff966593 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/ai-agent-action/components/WorkflowEditActionAiAgent.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/ai-agent-action/components/WorkflowEditActionAiAgent.tsx @@ -6,6 +6,7 @@ import { Select } from '@/ui/input/components/Select'; import { type WorkflowAiAgentAction } from '@/workflow/types/Workflow'; import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody'; import { WorkflowStepFooter } from '@/workflow/workflow-steps/components/WorkflowStepFooter'; +import { AI_AGENT_ACTION } from '@/workflow/workflow-steps/workflow-actions/constants/actions/AiAgentAction'; import { useWorkflowActionHeader } from '@/workflow/workflow-steps/workflow-actions/hooks/useWorkflowActionHeader'; import { WorkflowVariablePicker } from '@/workflow/workflow-variables/components/WorkflowVariablePicker'; import { type AiAgentOutputSchema } from '@/workflow/workflow-variables/types/AiAgentOutputSchema'; @@ -44,7 +45,7 @@ export const WorkflowEditActionAiAgent = ({ const { headerTitle, headerIcon, headerIconColor, headerType } = useWorkflowActionHeader({ action, - defaultTitle: 'AI Agent', + defaultTitle: AI_AGENT_ACTION.defaultLabel, }); const { handleOutputSchemaChange, outputFields } = useAiAgentOutputSchema( @@ -111,6 +112,7 @@ export const WorkflowEditActionAiAgent = ({ initialTitle={headerTitle} headerType={headerType} disabled={actionOptions.readonly} + iconTooltip={AI_AGENT_ACTION.defaultLabel} />
diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowEditActionServerlessFunction.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowEditActionServerlessFunction.tsx index d37bc841989c7..a8f7d4b24ddb5 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowEditActionServerlessFunction.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowEditActionServerlessFunction.tsx @@ -40,6 +40,7 @@ import { useLingui } from '@lingui/react/macro'; import { SOURCE_FOLDER_NAME } from '@/serverless-functions/constants/SourceFolderName'; import { computeNewSources } from '@/serverless-functions/utils/computeNewSources'; import { WorkflowStepFooter } from '@/workflow/workflow-steps/components/WorkflowStepFooter'; +import { CODE_ACTION } from '@/workflow/workflow-steps/workflow-actions/constants/actions/CodeAction'; import { type Monaco } from '@monaco-editor/react'; import { type editor } from 'monaco-editor'; import { AutoTypings } from 'monaco-editor-auto-typings'; @@ -326,7 +327,7 @@ export const WorkflowEditActionServerlessFunction = ({ const headerTitle = isDefined(action.name) ? action.name - : 'Code - Serverless Function'; + : CODE_ACTION.defaultLabel; const headerIcon = getActionIcon(action.type); const headerIconColor = useActionIconColorOrThrow(action.type); const headerType = useActionHeaderTypeOrThrow(action.type); @@ -431,6 +432,7 @@ export const WorkflowEditActionServerlessFunction = ({ initialTitle={headerTitle} headerType={headerType} disabled={actionOptions.readonly} + iconTooltip={CODE_ACTION.defaultLabel} /> {activeTabId === WorkflowServerlessFunctionTabId.CODE && ( diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionCreateRecord.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionCreateRecord.tsx index 2d8e8eadac39e..b750869bd5404 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionCreateRecord.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionCreateRecord.tsx @@ -10,6 +10,7 @@ import { useViewOrDefaultViewFromPrefetchedViews } from '@/views/hooks/useViewOr import { type WorkflowCreateRecordAction } from '@/workflow/types/Workflow'; import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody'; import { WorkflowStepFooter } from '@/workflow/workflow-steps/components/WorkflowStepFooter'; +import { CREATE_RECORD_ACTION } from '@/workflow/workflow-steps/workflow-actions/constants/actions/CreateRecordAction'; import { useWorkflowActionHeader } from '@/workflow/workflow-steps/workflow-actions/hooks/useWorkflowActionHeader'; import { shouldDisplayFormField } from '@/workflow/workflow-steps/workflow-actions/utils/shouldDisplayFormField'; import { WorkflowVariablePicker } from '@/workflow/workflow-variables/components/WorkflowVariablePicker'; @@ -198,7 +199,7 @@ export const WorkflowEditActionCreateRecord = ({ const { headerTitle, headerIcon, headerIconColor, headerType } = useWorkflowActionHeader({ action, - defaultTitle: 'Create Record', + defaultTitle: CREATE_RECORD_ACTION.defaultLabel, }); return ( @@ -219,6 +220,7 @@ export const WorkflowEditActionCreateRecord = ({ initialTitle={headerTitle} headerType={headerType} disabled={isFormDisabled} + iconTooltip={CREATE_RECORD_ACTION.defaultLabel} /> (action.settings.input); - const headerTitle = isDefined(action.name) ? action.name : `Form`; - const headerIcon = getActionIcon(action.type); - const headerIconColor = useActionIconColorOrThrow(action.type); - const headerType = useActionHeaderTypeOrThrow(action.type); + const { headerTitle, headerIcon, headerIconColor, headerType } = + useWorkflowActionHeader({ + action, + defaultTitle: FORM_ACTION.defaultLabel, + }); const [selectedField, setSelectedField] = useState(null); const [hoveredField, setHoveredField] = useState(null); @@ -239,6 +239,7 @@ export const WorkflowEditActionFormBuilder = ({ initialTitle={headerTitle} headerType={headerType} disabled={actionOptions.readonly} + iconTooltip={FORM_ACTION.defaultLabel} /> {formData.length === 0 && ( diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowEditActionFormFiller.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowEditActionFormFiller.tsx index 590061e221c06..a55ec8ae94e2f 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowEditActionFormFiller.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowEditActionFormFiller.tsx @@ -10,11 +10,11 @@ import { type WorkflowFormAction } from '@/workflow/types/Workflow'; import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody'; import { useUpdateWorkflowRunStep } from '@/workflow/workflow-steps/hooks/useUpdateWorkflowRunStep'; import { WorkflowFormFieldInput } from '@/workflow/workflow-steps/workflow-actions/components/WorkflowFormFieldInput'; +import { FORM_ACTION } from '@/workflow/workflow-steps/workflow-actions/constants/actions/FormAction'; import { useSubmitFormStep } from '@/workflow/workflow-steps/workflow-actions/form-action/hooks/useSubmitFormStep'; import { type WorkflowFormActionField } from '@/workflow/workflow-steps/workflow-actions/form-action/types/WorkflowFormActionField'; import { getDefaultFormFieldSettings } from '@/workflow/workflow-steps/workflow-actions/form-action/utils/getDefaultFormFieldSettings'; -import { getActionIcon } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIcon'; -import { useTheme } from '@emotion/react'; +import { useWorkflowActionHeader } from '@/workflow/workflow-steps/workflow-actions/hooks/useWorkflowActionHeader'; import { useEffect, useState } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { useIcons } from 'twenty-ui/display'; @@ -33,7 +33,6 @@ export const WorkflowEditActionFormFiller = ({ action, actionOptions, }: WorkflowEditActionFormFillerProps) => { - const theme = useTheme(); const { getIcon } = useIcons(); const { submitFormStep } = useSubmitFormStep(); const [formData, setFormData] = useState(action.settings.input); @@ -43,8 +42,12 @@ export const WorkflowEditActionFormFiller = ({ const [error, setError] = useState(undefined); const canSubmit = !actionOptions.readonly && !isDefined(error); - const headerTitle = isDefined(action.name) ? action.name : `Form`; - const headerIcon = getActionIcon(action.type); + + const { headerTitle, headerIcon, headerIconColor, headerType } = + useWorkflowActionHeader({ + action, + defaultTitle: FORM_ACTION.defaultLabel, + }); const onFieldUpdate = ({ fieldId, @@ -108,10 +111,11 @@ export const WorkflowEditActionFormFiller = ({ <> {formData.map((field) => { diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/http-request-action/components/WorkflowEditActionHttpRequest.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/http-request-action/components/WorkflowEditActionHttpRequest.tsx index 0e10d59a2e47d..be2b8fbd69894 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/http-request-action/components/WorkflowEditActionHttpRequest.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/http-request-action/components/WorkflowEditActionHttpRequest.tsx @@ -4,6 +4,7 @@ import { FormTextFieldInput } from '@/object-record/record-field/ui/form-types/c import { Select } from '@/ui/input/components/Select'; import { type WorkflowHttpRequestAction } from '@/workflow/types/Workflow'; import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody'; +import { HTTP_REQUEST_ACTION } from '@/workflow/workflow-steps/workflow-actions/constants/actions/HttpRequestAction'; import { useWorkflowActionHeader } from '@/workflow/workflow-steps/workflow-actions/hooks/useWorkflowActionHeader'; import { CmdEnterActionButton } from '@/action-menu/components/CmdEnterActionButton'; @@ -98,7 +99,7 @@ export const WorkflowEditActionHttpRequest = ({ const { headerTitle, headerIcon, headerIconColor, headerType } = useWorkflowActionHeader({ action, - defaultTitle: 'HTTP Request', + defaultTitle: HTTP_REQUEST_ACTION.defaultLabel, }); const { formData, handleFieldChange, saveAction } = useHttpRequestForm({ @@ -152,6 +153,7 @@ export const WorkflowEditActionHttpRequest = ({ initialTitle={headerTitle} headerType={headerType} disabled={actionOptions.readonly} + iconTooltip={HTTP_REQUEST_ACTION.defaultLabel} /> {activeTabId === WorkflowHttpRequestTabId.CONFIGURATION && ( diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/iterator-action/components/WorkflowEditActionIterator.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/iterator-action/components/WorkflowEditActionIterator.tsx index 6cec723060519..dd0864ebdf502 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/iterator-action/components/WorkflowEditActionIterator.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/iterator-action/components/WorkflowEditActionIterator.tsx @@ -5,6 +5,7 @@ import { type WorkflowIteratorAction } from '@/workflow/types/Workflow'; import { isStandaloneVariableString } from '@/workflow/utils/isStandaloneVariableString'; import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody'; import { WorkflowStepFooter } from '@/workflow/workflow-steps/components/WorkflowStepFooter'; +import { ITERATOR_ACTION } from '@/workflow/workflow-steps/workflow-actions/constants/actions/IteratorAction'; import { useWorkflowActionHeader } from '@/workflow/workflow-steps/workflow-actions/hooks/useWorkflowActionHeader'; import { WorkflowVariablePicker } from '@/workflow/workflow-variables/components/WorkflowVariablePicker'; import { useLingui } from '@lingui/react/macro'; @@ -46,7 +47,7 @@ export const WorkflowEditActionIterator = ({ const { headerTitle, headerIcon, headerIconColor, headerType, getIcon } = useWorkflowActionHeader({ action, - defaultTitle: 'Iterator', + defaultTitle: ITERATOR_ACTION.defaultLabel, }); const { t } = useLingui(); @@ -119,6 +120,7 @@ export const WorkflowEditActionIterator = ({ initialTitle={headerTitle} headerType={headerType} disabled={actionOptions.readonly} + iconTooltip={ITERATOR_ACTION.defaultLabel} /> { - it('should return "Code" for CODE action type', () => { - expect(getActionHeaderTypeOrThrow('CODE').message).toBe('Code'); + it('should return "Core" for CODE action type', () => { + expect(getActionHeaderTypeOrThrow('CODE').message).toBe('Core'); }); - it('should return "Action" for record-related action types', () => { + it('should return "Record" for record-related action types', () => { const recordActionTypes = [ 'CREATE_RECORD', 'UPDATE_RECORD', @@ -14,28 +14,23 @@ describe('getActionHeaderTypeOrThrow', () => { ] as const; recordActionTypes.forEach((type) => { - expect(getActionHeaderTypeOrThrow(type).message).toBe('Action'); + expect(getActionHeaderTypeOrThrow(type).message).toBe('Record'); }); }); - it('should return "Action" for FORM action type', () => { - expect(getActionHeaderTypeOrThrow('FORM').message).toBe('Action'); + it('should return "Human Input" for FORM action type', () => { + expect(getActionHeaderTypeOrThrow('FORM').message).toBe('Human Input'); }); - it('should return "Action" for SEND_EMAIL action type', () => { - expect(getActionHeaderTypeOrThrow('SEND_EMAIL').message).toBe('Action'); + it('should return "Core" for SEND_EMAIL action type', () => { + expect(getActionHeaderTypeOrThrow('SEND_EMAIL').message).toBe('Core'); }); - it('should return "HTTP Request" for HTTP_REQUEST action type', () => { - expect(getActionHeaderTypeOrThrow('HTTP_REQUEST').message).toBe( - 'HTTP Request', - ); + it('should return "Core" for HTTP_REQUEST action type', () => { + expect(getActionHeaderTypeOrThrow('HTTP_REQUEST').message).toBe('Core'); }); - it('should throw error for unknown action type', () => { - // @ts-expect-error Testing invalid action type - expect(() => getActionHeaderTypeOrThrow('UNKNOWN_ACTION')).toThrow( - 'Unsupported action type: UNKNOWN_ACTION', - ); + it('should return "AI" for AI_AGENT action type', () => { + expect(getActionHeaderTypeOrThrow('AI_AGENT').message).toBe('AI'); }); }); diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/utils/getActionHeaderTypeOrThrow.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/utils/getActionHeaderTypeOrThrow.ts index 6096fce8044f3..28b9d38b19bc8 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/utils/getActionHeaderTypeOrThrow.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/utils/getActionHeaderTypeOrThrow.ts @@ -1,40 +1,31 @@ import { type WorkflowActionType } from '@/workflow/types/Workflow'; +import { AI_ACTIONS } from '@/workflow/workflow-steps/workflow-actions/constants/AiActions'; +import { CORE_ACTIONS } from '@/workflow/workflow-steps/workflow-actions/constants/CoreActions'; +import { FLOW_ACTIONS } from '@/workflow/workflow-steps/workflow-actions/constants/FlowActions'; +import { HUMAN_INPUT_ACTIONS } from '@/workflow/workflow-steps/workflow-actions/constants/HumanInputActions'; +import { RECORD_ACTIONS } from '@/workflow/workflow-steps/workflow-actions/constants/RecordActions'; import { msg } from '@lingui/core/macro'; -import { assertUnreachable } from 'twenty-shared/utils'; export const getActionHeaderTypeOrThrow = (actionType: WorkflowActionType) => { - switch (actionType) { - case 'CODE': - return msg`Code`; - case 'CREATE_RECORD': - return msg`Create Record`; - case 'UPDATE_RECORD': - return msg`Update Record`; - case 'DELETE_RECORD': - case 'UPSERT_RECORD': - return msg`Delete Record`; - case 'FIND_RECORDS': - return msg`Find Records`; - case 'FORM': - return msg`Form`; - case 'SEND_EMAIL': - return msg`Send Email`; - case 'DELAY': - return msg`Delay`; - case 'HTTP_REQUEST': - return msg`HTTP Request`; - case 'AI_AGENT': - return msg`AI Agent`; - case 'FILTER': { - return msg`Filter`; - } - case 'ITERATOR': { - return msg`Iterator`; - } - case 'EMPTY': { - return msg`Add an Action`; - } - default: - assertUnreachable(actionType, `Unsupported action type: ${actionType}`); + if (FLOW_ACTIONS.some((action) => action.type === actionType)) { + return msg`Flow`; } + + if (CORE_ACTIONS.some((action) => action.type === actionType)) { + return msg`Core`; + } + + if (HUMAN_INPUT_ACTIONS.some((action) => action.type === actionType)) { + return msg`Human Input`; + } + + if (RECORD_ACTIONS.some((action) => action.type === actionType)) { + return msg`Record`; + } + + if (AI_ACTIONS.some((action) => action.type === actionType)) { + return msg`AI`; + } + + return msg`Action`; }; 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 03e43a71a2d26..97a479251bb92 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 @@ -82,6 +82,7 @@ export const WorkflowEditTriggerCronForm = ({ initialTitle={headerTitle} headerType={headerType} disabled={triggerOptions.readonly} + iconTooltip={getTriggerDefaultLabel(trigger)} /> = [ - { - defaultLabel: DatabaseTriggerDefaultLabel.RECORD_IS_CREATED, - type: 'DATABASE_EVENT', - icon: 'IconPlaylistAdd', - event: 'created', - }, - { - defaultLabel: DatabaseTriggerDefaultLabel.RECORD_IS_UPDATED, - type: 'DATABASE_EVENT', - icon: 'IconRefreshDot', - event: 'updated', - }, - { - defaultLabel: DatabaseTriggerDefaultLabel.RECORD_IS_DELETED, - type: 'DATABASE_EVENT', - icon: 'IconTrash', - event: 'deleted', - }, - { - defaultLabel: DatabaseTriggerDefaultLabel.RECORD_UPSERTED, - type: 'DATABASE_EVENT', - icon: 'IconPencilPlus', - event: 'upserted', - }, + RECORD_IS_CREATED_TRIGGER, + RECORD_IS_UPDATED_TRIGGER, + RECORD_IS_DELETED_TRIGGER, + RECORD_UPSERTED_TRIGGER, ]; diff --git a/packages/twenty-front/src/modules/workflow/workflow-trigger/constants/OtherTriggerTypes.ts b/packages/twenty-front/src/modules/workflow/workflow-trigger/constants/OtherTriggerTypes.ts index 0e1e9ad395056..b3e50b3933357 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-trigger/constants/OtherTriggerTypes.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-trigger/constants/OtherTriggerTypes.ts @@ -1,23 +1,10 @@ import { type WorkflowTriggerType } from '@/workflow/types/Workflow'; +import { CRON_TRIGGER } from '@/workflow/workflow-trigger/constants/triggers/CronTrigger'; +import { MANUAL_TRIGGER } from '@/workflow/workflow-trigger/constants/triggers/ManualTrigger'; +import { WEBHOOK_TRIGGER } from '@/workflow/workflow-trigger/constants/triggers/WebhookTrigger'; export const OTHER_TRIGGER_TYPES: Array<{ defaultLabel: string; type: WorkflowTriggerType; icon: string; -}> = [ - { - defaultLabel: 'Launch manually', - type: 'MANUAL', - icon: 'IconHandMove', - }, - { - defaultLabel: 'On a schedule', - type: 'CRON', - icon: 'IconClock', - }, - { - defaultLabel: 'Webhook', - type: 'WEBHOOK', - icon: 'IconWebhook', - }, -]; +}> = [MANUAL_TRIGGER, CRON_TRIGGER, WEBHOOK_TRIGGER]; diff --git a/packages/twenty-front/src/modules/workflow/workflow-trigger/constants/triggers/CronTrigger.ts b/packages/twenty-front/src/modules/workflow/workflow-trigger/constants/triggers/CronTrigger.ts new file mode 100644 index 0000000000000..eec33f65f4d20 --- /dev/null +++ b/packages/twenty-front/src/modules/workflow/workflow-trigger/constants/triggers/CronTrigger.ts @@ -0,0 +1,11 @@ +import { type WorkflowTriggerType } from '@/workflow/types/Workflow'; + +export const CRON_TRIGGER: { + defaultLabel: string; + type: WorkflowTriggerType; + icon: string; +} = { + defaultLabel: 'On a schedule', + type: 'CRON', + icon: 'IconClock', +}; diff --git a/packages/twenty-front/src/modules/workflow/workflow-trigger/constants/triggers/ManualTrigger.ts b/packages/twenty-front/src/modules/workflow/workflow-trigger/constants/triggers/ManualTrigger.ts new file mode 100644 index 0000000000000..75fd4db7880f6 --- /dev/null +++ b/packages/twenty-front/src/modules/workflow/workflow-trigger/constants/triggers/ManualTrigger.ts @@ -0,0 +1,11 @@ +import { type WorkflowTriggerType } from '@/workflow/types/Workflow'; + +export const MANUAL_TRIGGER: { + defaultLabel: string; + type: WorkflowTriggerType; + icon: string; +} = { + defaultLabel: 'Launch manually', + type: 'MANUAL', + icon: 'IconHandMove', +}; diff --git a/packages/twenty-front/src/modules/workflow/workflow-trigger/constants/triggers/RecordIsCreatedTrigger.ts b/packages/twenty-front/src/modules/workflow/workflow-trigger/constants/triggers/RecordIsCreatedTrigger.ts new file mode 100644 index 0000000000000..3680580620f52 --- /dev/null +++ b/packages/twenty-front/src/modules/workflow/workflow-trigger/constants/triggers/RecordIsCreatedTrigger.ts @@ -0,0 +1,14 @@ +import { type WorkflowTriggerType } from '@/workflow/types/Workflow'; +import { DatabaseTriggerDefaultLabel } from '@/workflow/workflow-trigger/constants/DatabaseTriggerDefaultLabel'; + +export const RECORD_IS_CREATED_TRIGGER: { + defaultLabel: DatabaseTriggerDefaultLabel; + type: WorkflowTriggerType; + icon: string; + event: string; +} = { + defaultLabel: DatabaseTriggerDefaultLabel.RECORD_IS_CREATED, + type: 'DATABASE_EVENT', + icon: 'IconPlaylistAdd', + event: 'created', +}; diff --git a/packages/twenty-front/src/modules/workflow/workflow-trigger/constants/triggers/RecordIsDeletedTrigger.ts b/packages/twenty-front/src/modules/workflow/workflow-trigger/constants/triggers/RecordIsDeletedTrigger.ts new file mode 100644 index 0000000000000..d0696a76ef481 --- /dev/null +++ b/packages/twenty-front/src/modules/workflow/workflow-trigger/constants/triggers/RecordIsDeletedTrigger.ts @@ -0,0 +1,14 @@ +import { type WorkflowTriggerType } from '@/workflow/types/Workflow'; +import { DatabaseTriggerDefaultLabel } from '@/workflow/workflow-trigger/constants/DatabaseTriggerDefaultLabel'; + +export const RECORD_IS_DELETED_TRIGGER: { + defaultLabel: DatabaseTriggerDefaultLabel; + type: WorkflowTriggerType; + icon: string; + event: string; +} = { + defaultLabel: DatabaseTriggerDefaultLabel.RECORD_IS_DELETED, + type: 'DATABASE_EVENT', + icon: 'IconTrash', + event: 'deleted', +}; diff --git a/packages/twenty-front/src/modules/workflow/workflow-trigger/constants/triggers/RecordIsUpdatedTrigger.ts b/packages/twenty-front/src/modules/workflow/workflow-trigger/constants/triggers/RecordIsUpdatedTrigger.ts new file mode 100644 index 0000000000000..c2563675a52a3 --- /dev/null +++ b/packages/twenty-front/src/modules/workflow/workflow-trigger/constants/triggers/RecordIsUpdatedTrigger.ts @@ -0,0 +1,14 @@ +import { type WorkflowTriggerType } from '@/workflow/types/Workflow'; +import { DatabaseTriggerDefaultLabel } from '@/workflow/workflow-trigger/constants/DatabaseTriggerDefaultLabel'; + +export const RECORD_IS_UPDATED_TRIGGER: { + defaultLabel: DatabaseTriggerDefaultLabel; + type: WorkflowTriggerType; + icon: string; + event: string; +} = { + defaultLabel: DatabaseTriggerDefaultLabel.RECORD_IS_UPDATED, + type: 'DATABASE_EVENT', + icon: 'IconRefreshDot', + event: 'updated', +}; diff --git a/packages/twenty-front/src/modules/workflow/workflow-trigger/constants/triggers/RecordUpsertedTrigger.ts b/packages/twenty-front/src/modules/workflow/workflow-trigger/constants/triggers/RecordUpsertedTrigger.ts new file mode 100644 index 0000000000000..757f30b240fd7 --- /dev/null +++ b/packages/twenty-front/src/modules/workflow/workflow-trigger/constants/triggers/RecordUpsertedTrigger.ts @@ -0,0 +1,14 @@ +import { type WorkflowTriggerType } from '@/workflow/types/Workflow'; +import { DatabaseTriggerDefaultLabel } from '@/workflow/workflow-trigger/constants/DatabaseTriggerDefaultLabel'; + +export const RECORD_UPSERTED_TRIGGER: { + defaultLabel: DatabaseTriggerDefaultLabel; + type: WorkflowTriggerType; + icon: string; + event: string; +} = { + defaultLabel: DatabaseTriggerDefaultLabel.RECORD_UPSERTED, + type: 'DATABASE_EVENT', + icon: 'IconPencilPlus', + event: 'upserted', +}; diff --git a/packages/twenty-front/src/modules/workflow/workflow-trigger/constants/triggers/WebhookTrigger.ts b/packages/twenty-front/src/modules/workflow/workflow-trigger/constants/triggers/WebhookTrigger.ts new file mode 100644 index 0000000000000..82af499c782a4 --- /dev/null +++ b/packages/twenty-front/src/modules/workflow/workflow-trigger/constants/triggers/WebhookTrigger.ts @@ -0,0 +1,11 @@ +import { type WorkflowTriggerType } from '@/workflow/types/Workflow'; + +export const WEBHOOK_TRIGGER: { + defaultLabel: string; + type: WorkflowTriggerType; + icon: string; +} = { + defaultLabel: 'Webhook', + type: 'WEBHOOK', + icon: 'IconWebhook', +}; diff --git a/packages/twenty-front/src/modules/workflow/workflow-trigger/utils/__tests__/getTriggerHeaderType.test.ts b/packages/twenty-front/src/modules/workflow/workflow-trigger/utils/__tests__/getTriggerHeaderType.test.ts index ddeb7025078df..25b3b8f778e48 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-trigger/utils/__tests__/getTriggerHeaderType.test.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-trigger/utils/__tests__/getTriggerHeaderType.test.ts @@ -115,7 +115,7 @@ describe('getTriggerHeaderType', () => { const result = getTriggerHeaderType(trigger); - expect(result).toBe('Trigger'); + expect(result).toBe('Trigger · Cron'); }); it('returns "Trigger" for cron trigger with HOURS schedule', () => { @@ -134,7 +134,7 @@ describe('getTriggerHeaderType', () => { const result = getTriggerHeaderType(trigger); - expect(result).toBe('Trigger'); + expect(result).toBe('Trigger · Cron'); }); it('returns "Trigger" for cron trigger with MINUTES schedule', () => { @@ -152,7 +152,7 @@ describe('getTriggerHeaderType', () => { const result = getTriggerHeaderType(trigger); - expect(result).toBe('Trigger'); + expect(result).toBe('Trigger · Cron'); }); it('returns "Trigger" for cron trigger with CUSTOM schedule', () => { @@ -168,7 +168,7 @@ describe('getTriggerHeaderType', () => { const result = getTriggerHeaderType(trigger); - expect(result).toBe('Trigger'); + expect(result).toBe('Trigger · Cron'); }); }); diff --git a/packages/twenty-front/src/modules/workflow/workflow-trigger/utils/getTriggerHeaderType.ts b/packages/twenty-front/src/modules/workflow/workflow-trigger/utils/getTriggerHeaderType.ts index 02cec7b04c055..ff4d53267cc14 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-trigger/utils/getTriggerHeaderType.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-trigger/utils/getTriggerHeaderType.ts @@ -5,7 +5,7 @@ import { assertUnreachable } from 'twenty-shared/utils'; export const getTriggerHeaderType = (trigger: WorkflowTrigger) => { switch (trigger.type) { case 'CRON': { - return 'Trigger'; + return 'Trigger · Cron'; } case 'WEBHOOK': { return 'Trigger · Webhook';