Fix icon matching + small other fixes on workflows (#9814)

- Record Fields label
- body height fix
- Icons on object picker
- Fix icon matching between nodes and right drawer

<img width="1296" alt="Capture d’écran 2025-01-23 à 18 51 12"
src="https://github.com/user-attachments/assets/ecd5fb00-49cd-416e-96af-9200418294e0"
/>
This commit is contained in:
Thomas Trompette
2025-01-24 15:47:09 +01:00
committed by GitHub
parent 1a42483aa9
commit 29df6e64a0
33 changed files with 247 additions and 226 deletions

View File

@ -7,6 +7,7 @@ const StyledWorkflowStepBody = styled.div`
padding: ${({ theme }) => theme.spacing(6)};
row-gap: ${({ theme }) => theme.spacing(6)};
flex: 1 1 auto;
height: 100%;
`;
export { StyledWorkflowStepBody as WorkflowStepBody };

View File

@ -7,17 +7,18 @@ import {
WorkflowWithCurrentVersion,
} from '@/workflow/types/Workflow';
import { workflowSelectedNodeState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeState';
import { getWorkflowNodeIcon } from '@/workflow/workflow-diagram/utils/getWorkflowNodeIcon';
import { getWorkflowNodeIconKey } from '@/workflow/workflow-diagram/utils/getWorkflowNodeIconKey';
import { useCreateWorkflowVersionStep } from '@/workflow/workflow-steps/hooks/useCreateWorkflowVersionStep';
import { workflowCreateStepFromParentStepIdState } from '@/workflow/workflow-steps/states/workflowCreateStepFromParentStepIdState';
import { useRecoilValue, useSetRecoilState } from 'recoil';
import { isDefined } from 'twenty-ui';
import { isDefined, useIcons } from 'twenty-ui';
export const useCreateStep = ({
workflow,
}: {
workflow: WorkflowWithCurrentVersion;
}) => {
const { getIcon } = useIcons();
const { createWorkflowVersionStep } = useCreateWorkflowVersionStep();
const setWorkflowSelectedNode = useSetRecoilState(workflowSelectedNodeState);
const setWorkflowLastCreatedStepId = useSetRecoilState(
@ -53,12 +54,15 @@ export const useCreateStep = ({
setWorkflowSelectedNode(createdStep.id);
setWorkflowLastCreatedStepId(createdStep.id);
const stepIcon = getWorkflowNodeIconKey({
nodeType: 'action',
actionType: createdStep.type as WorkflowStepType,
name: createdStep.name,
});
openRightDrawer(RightDrawerPages.WorkflowStepEdit, {
title: createdStep.name,
Icon: getWorkflowNodeIcon({
nodeType: 'action',
actionType: createdStep.type as WorkflowStepType,
}),
Icon: getIcon(stepIcon),
});
};

View File

@ -3,7 +3,7 @@ import { useCreateStep } from '@/workflow/workflow-steps/hooks/useCreateStep';
import { OTHER_ACTIONS } from '@/workflow/workflow-steps/workflow-actions/constants/OtherActions';
import { RECORD_ACTIONS } from '@/workflow/workflow-steps/workflow-actions/constants/RecordActions';
import styled from '@emotion/styled';
import { MenuItem } from 'twenty-ui';
import { MenuItem, useIcons } from 'twenty-ui';
const StyledActionListContainer = styled.div`
display: flex;
@ -30,6 +30,7 @@ export const RightDrawerWorkflowSelectActionContent = ({
}: {
workflow: WorkflowWithCurrentVersion;
}) => {
const { getIcon } = useIcons();
const { createStep } = useCreateStep({
workflow,
});
@ -40,7 +41,7 @@ export const RightDrawerWorkflowSelectActionContent = ({
{RECORD_ACTIONS.map((action) => (
<MenuItem
key={action.type}
LeftIcon={action.icon}
LeftIcon={getIcon(action.icon)}
text={action.label}
onClick={() => createStep(action.type)}
/>
@ -49,7 +50,7 @@ export const RightDrawerWorkflowSelectActionContent = ({
{OTHER_ACTIONS.map((action) => (
<MenuItem
key={action.type}
LeftIcon={action.icon}
LeftIcon={getIcon(action.icon)}
text={action.label}
onClick={() => createStep(action.type)}
/>

View File

@ -7,15 +7,11 @@ import { useViewOrDefaultViewFromPrefetchedViews } from '@/views/hooks/useViewOr
import { WorkflowCreateRecordAction } from '@/workflow/types/Workflow';
import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody';
import { WorkflowStepHeader } from '@/workflow/workflow-steps/components/WorkflowStepHeader';
import { getActionIcon } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIcon';
import { WorkflowVariablePicker } from '@/workflow/workflow-variables/components/WorkflowVariablePicker';
import { useTheme } from '@emotion/react';
import { useEffect, useState } from 'react';
import {
HorizontalSeparator,
IconAddressBook,
isDefined,
useIcons,
} from 'twenty-ui';
import { HorizontalSeparator, isDefined, useIcons } from 'twenty-ui';
import { JsonValue } from 'type-fest';
import { useDebouncedCallback } from 'use-debounce';
import { FieldMetadataType } from '~/generated/graphql';
@ -162,6 +158,7 @@ export const WorkflowEditActionFormCreateRecord = ({
}, [saveAction]);
const headerTitle = isDefined(action.name) ? action.name : `Create Record`;
const headerIcon = getActionIcon(action.type);
return (
<>
@ -176,7 +173,7 @@ export const WorkflowEditActionFormCreateRecord = ({
name: newName,
});
}}
Icon={IconAddressBook}
Icon={getIcon(headerIcon)}
iconColor={theme.font.color.tertiary}
initialTitle={headerTitle}
headerType="Action"

View File

@ -5,14 +5,10 @@ import { WorkflowStepHeader } from '@/workflow/workflow-steps/components/Workflo
import { WorkflowSingleRecordPicker } from '@/workflow/workflow-steps/workflow-actions/components/WorkflowSingleRecordPicker';
import { useTheme } from '@emotion/react';
import { useEffect, useState } from 'react';
import {
HorizontalSeparator,
IconAddressBook,
isDefined,
useIcons,
} from 'twenty-ui';
import { HorizontalSeparator, isDefined, useIcons } from 'twenty-ui';
import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody';
import { getActionIcon } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIcon';
import { JsonValue } from 'type-fest';
import { useDebouncedCallback } from 'use-debounce';
@ -110,6 +106,7 @@ export const WorkflowEditActionFormDeleteRecord = ({
}, [saveAction]);
const headerTitle = isDefined(action.name) ? action.name : `Delete Record`;
const headerIcon = getActionIcon(action.type);
return (
<>
@ -124,7 +121,7 @@ export const WorkflowEditActionFormDeleteRecord = ({
name: newName,
});
}}
Icon={IconAddressBook}
Icon={getIcon(headerIcon)}
iconColor={theme.font.color.tertiary}
initialTitle={headerTitle}
headerType="Action"

View File

@ -9,11 +9,12 @@ import { workflowIdState } from '@/workflow/states/workflowIdState';
import { WorkflowSendEmailAction } from '@/workflow/types/Workflow';
import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody';
import { WorkflowStepHeader } from '@/workflow/workflow-steps/components/WorkflowStepHeader';
import { getActionIcon } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIcon';
import { WorkflowVariablePicker } from '@/workflow/workflow-variables/components/WorkflowVariablePicker';
import { useTheme } from '@emotion/react';
import { useEffect, useState } from 'react';
import { useRecoilValue } from 'recoil';
import { IconMail, IconPlus, isDefined } from 'twenty-ui';
import { IconPlus, isDefined, useIcons } from 'twenty-ui';
import { JsonValue } from 'type-fest';
import { useDebouncedCallback } from 'use-debounce';
@ -41,6 +42,7 @@ export const WorkflowEditActionFormSendEmail = ({
actionOptions,
}: WorkflowEditActionFormSendEmailProps) => {
const theme = useTheme();
const { getIcon } = useIcons();
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
const { triggerApisOAuth } = useTriggerApisOAuth();
@ -165,6 +167,7 @@ export const WorkflowEditActionFormSendEmail = ({
});
const headerTitle = isDefined(action.name) ? action.name : 'Send Email';
const headerIcon = getActionIcon(action.type);
return (
!loading && (
@ -180,7 +183,7 @@ export const WorkflowEditActionFormSendEmail = ({
name: newName,
});
}}
Icon={IconMail}
Icon={getIcon(headerIcon)}
iconColor={theme.color.blue}
initialTitle={headerTitle}
headerType="Email"

View File

@ -23,6 +23,7 @@ import { serverlessFunctionTestDataFamilyState } from '@/workflow/states/serverl
import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody';
import { WorkflowEditActionFormServerlessFunctionFields } from '@/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionFormServerlessFunctionFields';
import { WORKFLOW_SERVERLESS_FUNCTION_TAB_LIST_COMPONENT_ID } from '@/workflow/workflow-steps/workflow-actions/constants/WorkflowServerlessFunctionTabListComponentId';
import { getActionIcon } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIcon';
import { getWrongExportedFunctionMarkers } from '@/workflow/workflow-steps/workflow-actions/utils/getWrongExportedFunctionMarkers';
import { WorkflowVariablePicker } from '@/workflow/workflow-variables/components/WorkflowVariablePicker';
import { useTheme } from '@emotion/react';
@ -32,7 +33,13 @@ import { editor } from 'monaco-editor';
import { AutoTypings } from 'monaco-editor-auto-typings';
import { useEffect, useState } from 'react';
import { useRecoilState, useRecoilValue } from 'recoil';
import { CodeEditor, IconCode, IconPlayerPlay, isDefined } from 'twenty-ui';
import {
CodeEditor,
IconCode,
IconPlayerPlay,
isDefined,
useIcons,
} from 'twenty-ui';
import { useDebouncedCallback } from 'use-debounce';
const StyledContainer = styled.div`
@ -76,10 +83,11 @@ export const WorkflowEditActionFormServerlessFunction = ({
action,
actionOptions,
}: WorkflowEditActionFormServerlessFunctionProps) => {
const theme = useTheme();
const { getIcon } = useIcons();
const serverlessFunctionId = action.settings.input.serverlessFunctionId;
const serverlessFunctionVersion =
action.settings.input.serverlessFunctionVersion;
const theme = useTheme();
const tabListId = `${WORKFLOW_SERVERLESS_FUNCTION_TAB_LIST_COMPONENT_ID}_${serverlessFunctionId}`;
const { activeTabId, setActiveTabId } = useTabList(tabListId);
const { updateOneServerlessFunction, isReady } =
@ -270,6 +278,11 @@ export const WorkflowEditActionFormServerlessFunction = ({
setFunctionInput(action.settings.input.serverlessFunctionInput);
}, [action]);
const headerTitle = isDefined(action.name)
? action.name
: 'Code - Serverless Function';
const headerIcon = getActionIcon(action.type);
return (
!loading && (
<StyledContainer>
@ -284,9 +297,9 @@ export const WorkflowEditActionFormServerlessFunction = ({
onTitleChange={(newName: string) => {
updateAction({ name: newName });
}}
Icon={IconCode}
Icon={getIcon(headerIcon)}
iconColor={theme.color.orange}
initialTitle={action.name || 'Code - Serverless Function'}
initialTitle={headerTitle}
headerType="Code"
/>
<WorkflowStepBody>

View File

@ -3,12 +3,7 @@ import { Select, SelectOption } from '@/ui/input/components/Select';
import { WorkflowUpdateRecordAction } from '@/workflow/types/Workflow';
import { useTheme } from '@emotion/react';
import { useEffect, useState } from 'react';
import {
HorizontalSeparator,
IconAddressBook,
isDefined,
useIcons,
} from 'twenty-ui';
import { HorizontalSeparator, isDefined, useIcons } from 'twenty-ui';
import { formatFieldMetadataItemAsFieldDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsFieldDefinition';
import { FormFieldInput } from '@/object-record/record-field/components/FormFieldInput';
@ -16,6 +11,7 @@ import { FormMultiSelectFieldInput } from '@/object-record/record-field/form-typ
import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody';
import { WorkflowStepHeader } from '@/workflow/workflow-steps/components/WorkflowStepHeader';
import { WorkflowSingleRecordPicker } from '@/workflow/workflow-steps/workflow-actions/components/WorkflowSingleRecordPicker';
import { getActionIcon } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIcon';
import { WorkflowVariablePicker } from '@/workflow/workflow-variables/components/WorkflowVariablePicker';
import { JsonValue } from 'type-fest';
import { useDebouncedCallback } from 'use-debounce';
@ -157,6 +153,7 @@ export const WorkflowEditActionFormUpdateRecord = ({
}, [saveAction]);
const headerTitle = isDefined(action.name) ? action.name : `Update Record`;
const headerIcon = getActionIcon(action.type);
return (
<>
@ -171,7 +168,7 @@ export const WorkflowEditActionFormUpdateRecord = ({
name: newName,
});
}}
Icon={IconAddressBook}
Icon={getIcon(headerIcon)}
iconColor={theme.font.color.tertiary}
initialTitle={headerTitle}
headerType="Action"

View File

@ -1,19 +1,18 @@
import { WorkflowStepType } from '@/workflow/types/Workflow';
import { IconCode, IconComponent, IconSend } from 'twenty-ui';
export const OTHER_ACTIONS: Array<{
label: string;
type: WorkflowStepType;
icon: IconComponent;
icon: string;
}> = [
{
label: 'Send Email',
type: 'SEND_EMAIL',
icon: IconSend,
icon: 'IconSend',
},
{
label: 'Code',
type: 'CODE',
icon: IconCode,
icon: 'IconCode',
},
];

View File

@ -1,24 +1,23 @@
import { WorkflowStepType } from '@/workflow/types/Workflow';
import { IconComponent, IconPlus, IconRefreshDot, IconTrash } from 'twenty-ui';
export const RECORD_ACTIONS: Array<{
label: string;
type: WorkflowStepType;
icon: IconComponent;
icon: string;
}> = [
{
label: 'Create Record',
type: 'CREATE_RECORD',
icon: IconPlus,
icon: 'IconPlus',
},
{
label: 'Update Record',
type: 'UPDATE_RECORD',
icon: IconRefreshDot,
icon: 'IconRefreshDot',
},
{
label: 'Delete Record',
type: 'DELETE_RECORD',
icon: IconTrash,
icon: 'IconTrash',
},
];

View File

@ -0,0 +1,13 @@
import { OTHER_ACTIONS } from '@/workflow/workflow-steps/workflow-actions/constants/OtherActions';
import { RECORD_ACTIONS } from '@/workflow/workflow-steps/workflow-actions/constants/RecordActions';
export const getActionIcon = (actionType: string) => {
switch (actionType) {
case 'CREATE_RECORD':
case 'UPDATE_RECORD':
case 'DELETE_RECORD':
return RECORD_ACTIONS.find((item) => item.type === actionType)?.icon;
default:
return OTHER_ACTIONS.find((item) => item.type === actionType)?.icon;
}
};