Put delete button on step footer + add unique fields on upsert action (#15497)
<img width="491" height="823" alt="Capture d’écran 2025-10-31 à 14 54 38" src="https://github.com/user-attachments/assets/8058a6a3-8a6c-4cdd-93d9-2af71208dc5a" />
This commit is contained in:
+30
-9
@@ -11,6 +11,7 @@ import { useDuplicateStep } from '@/workflow/workflow-steps/hooks/useDuplicateSt
|
||||
import { useTheme } from '@emotion/react';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { useId } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { TRIGGER_STEP_ID } from 'twenty-shared/workflow';
|
||||
import { IconCopyPlus, IconPencil, IconTrash } from 'twenty-ui/display';
|
||||
import { Button } from 'twenty-ui/input';
|
||||
@@ -35,6 +36,8 @@ export const WorkflowStepFooter = ({
|
||||
openWorkflowTriggerTypeInCommandMenu,
|
||||
} = useWorkflowCommandMenu();
|
||||
const { deleteStep } = useDeleteStep();
|
||||
const shouldPinDeleteButton =
|
||||
!isDefined(additionalActions) || additionalActions.length === 0;
|
||||
|
||||
const OptionsDropdown = (
|
||||
<Dropdown
|
||||
@@ -77,14 +80,16 @@ export const WorkflowStepFooter = ({
|
||||
LeftIcon={IconCopyPlus}
|
||||
/>
|
||||
)}
|
||||
<MenuItem
|
||||
onClick={() => {
|
||||
closeDropdown(dropdownId);
|
||||
deleteStep(stepId);
|
||||
}}
|
||||
text={t`Delete node`}
|
||||
LeftIcon={IconTrash}
|
||||
/>
|
||||
{!shouldPinDeleteButton && (
|
||||
<MenuItem
|
||||
onClick={() => {
|
||||
closeDropdown(dropdownId);
|
||||
deleteStep(stepId);
|
||||
}}
|
||||
text={t`Delete node`}
|
||||
LeftIcon={IconTrash}
|
||||
/>
|
||||
)}
|
||||
</SelectableList>
|
||||
</DropdownMenuItemsContainer>
|
||||
</DropdownContent>
|
||||
@@ -92,9 +97,25 @@ export const WorkflowStepFooter = ({
|
||||
/>
|
||||
);
|
||||
|
||||
const deleteButton = (
|
||||
<Button
|
||||
title="Delete"
|
||||
onClick={() => {
|
||||
deleteStep(stepId);
|
||||
}}
|
||||
Icon={IconTrash}
|
||||
accent="danger"
|
||||
inverted
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<RightDrawerFooter
|
||||
actions={[OptionsDropdown, ...(additionalActions ?? [])]}
|
||||
actions={[
|
||||
OptionsDropdown,
|
||||
...(additionalActions ?? []),
|
||||
...(shouldPinDeleteButton ? [deleteButton] : []),
|
||||
]}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
+27
@@ -6,10 +6,12 @@ import { isFieldRelation } from '@/object-record/record-field/ui/types/guards/is
|
||||
import { Select } from '@/ui/input/components/Select';
|
||||
import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
|
||||
import { useViewOrDefaultViewFromPrefetchedViews } from '@/views/hooks/useViewOrDefaultViewFromPrefetchedViews';
|
||||
import { WorkflowFieldsMultiSelect } from '@/workflow/components/WorkflowEditUpdateEventFieldsMultiSelect';
|
||||
import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody';
|
||||
import { shouldDisplayFormField } from '@/workflow/workflow-steps/workflow-actions/utils/shouldDisplayFormField';
|
||||
import { WorkflowVariablePicker } from '@/workflow/workflow-variables/components/WorkflowVariablePicker';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { canObjectBeManagedByWorkflow } from 'twenty-shared/workflow';
|
||||
@@ -96,6 +98,8 @@ export const WorkflowCreateRecordBody = ({
|
||||
(item) => item.nameSingular === objectNameSingular,
|
||||
);
|
||||
|
||||
const objectLabelSingular = objectMetadataItem?.labelSingular;
|
||||
|
||||
const { view: indexView } = useViewOrDefaultViewFromPrefetchedViews({
|
||||
objectMetadataItemId: objectMetadataItem?.id ?? '',
|
||||
});
|
||||
@@ -117,6 +121,10 @@ export const WorkflowCreateRecordBody = ({
|
||||
})
|
||||
.sort(sortByViewFieldPosition);
|
||||
|
||||
const uniqueFieldMetadataItems = inlineFieldMetadataItems?.filter(
|
||||
(fieldMetadataItem) => fieldMetadataItem.isUnique,
|
||||
);
|
||||
|
||||
const inlineFieldDefinitions = isDefined(objectMetadataItem)
|
||||
? inlineFieldMetadataItems?.map((fieldMetadataItem) =>
|
||||
formatFieldMetadataItemAsFieldDefinition({
|
||||
@@ -206,6 +214,25 @@ export const WorkflowCreateRecordBody = ({
|
||||
dropdownWidth={GenericDropdownContentWidth.ExtraLarge}
|
||||
/>
|
||||
|
||||
{actionType === 'UPSERT_RECORD' &&
|
||||
isDefined(objectMetadataItem) &&
|
||||
isDefined(uniqueFieldMetadataItems) &&
|
||||
uniqueFieldMetadataItems.length > 0 && (
|
||||
<WorkflowFieldsMultiSelect
|
||||
label={t`Unique fields`}
|
||||
objectMetadataItem={objectMetadataItem}
|
||||
handleFieldsChange={() => {}}
|
||||
defaultFields={
|
||||
uniqueFieldMetadataItems?.map(
|
||||
(fieldMetadataItem) => fieldMetadataItem.name,
|
||||
) ?? []
|
||||
}
|
||||
placeholder={t`Object unique fields`}
|
||||
readonly
|
||||
hint={t`We match on these fields. If a ${objectLabelSingular} already exists, we update it. Otherwise, we create a new one.`}
|
||||
/>
|
||||
)}
|
||||
|
||||
<HorizontalSeparator noMargin />
|
||||
|
||||
{inlineFieldDefinitions?.map((fieldDefinition) => {
|
||||
|
||||
Reference in New Issue
Block a user