Support actor filtering in workflows (#16783)

Fixes https://github.com/twentyhq/twenty/issues/15782

Find records
<img width="422" height="423" alt="Capture d’écran 2025-12-23 à 16 23
49"
src="https://github.com/user-attachments/assets/5856de06-d608-46f6-97a6-8f382f355a44"
/>

Filters
<img width="422" height="271" alt="Capture d’écran 2025-12-23 à 16 23
32"
src="https://github.com/user-attachments/assets/fcc10b6e-f1ec-497a-8593-d599164d4e4b"
/>

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Adds full support for filtering on `ACTOR` composite fields across UI
and server.
> 
> - Front-end: handles `ACTOR` in advanced filters and workflow filters;
`source` uses multi-select options from `FieldActorSource`,
`workspaceMemberId` uses `FormSingleRecordPicker`, others default to
text
> - Updates operand mapping for `ACTOR` (`source`→`SELECT`,
`workspaceMemberId`→`RELATION`, else `TEXT`)
> - Server: adds `ACTOR` evaluation with subfield-specific logic
(delegates to select/relation/text evaluators)
> - Simplifies `AdvancedFilterFieldSelectMenu` by removing
workflow-specific field filtering
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
7a8164cd2d4cad321ff1009bc7d1c4295a6672ca. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Félix Malfait <felix@twenty.com>
This commit is contained in:
Thomas Trompette
2025-12-30 10:34:08 +01:00
committed by GitHub
parent d39f105a03
commit a2827494a1
8 changed files with 90 additions and 19 deletions
@@ -23,7 +23,6 @@ type WorkflowStepFilterFieldSelectProps = {
};
const NON_SELECTABLE_FIELD_TYPES = [
FieldMetadataType.ACTOR,
FieldMetadataType.RICH_TEXT_V2,
FieldMetadataType.RATING,
];
@@ -1,14 +1,23 @@
import { FormCountryMultiSelectInput } from '@/object-record/record-field/ui/form-types/components/FormCountryMultiSelectInput';
import { FormMultiSelectFieldInput } from '@/object-record/record-field/ui/form-types/components/FormMultiSelectFieldInput';
import { FormNumberFieldInput } from '@/object-record/record-field/ui/form-types/components/FormNumberFieldInput';
import { FormSingleRecordPicker } from '@/object-record/record-field/ui/form-types/components/FormSingleRecordPicker';
import { FormTextFieldInput } from '@/object-record/record-field/ui/form-types/components/FormTextFieldInput';
import { CURRENCIES } from '@/settings/data-model/constants/Currencies';
import { WorkflowStepFilterContext } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/context/WorkflowStepFilterContext';
import { WorkflowVariablePicker } from '@/workflow/workflow-variables/components/WorkflowVariablePicker';
import { useContext } from 'react';
import { type StepFilter } from 'twenty-shared/types';
import { FieldActorSource, type StepFilter } from 'twenty-shared/types';
import { type SelectOption } from 'twenty-ui/input';
import { type JsonValue } from 'type-fest';
const ACTOR_SOURCE_OPTIONS: SelectOption[] = Object.values(
FieldActorSource,
).map((source) => ({
label: source.charAt(0) + source.slice(1).toLowerCase(),
value: source,
}));
export const WorkflowStepFilterValueCompositeInput = ({
stepFilter,
onChange,
@@ -71,6 +80,31 @@ export const WorkflowStepFilterValueCompositeInput = ({
readonly={readonly}
/>
)
) : filterType === 'ACTOR' ? (
subFieldName === 'source' ? (
<FormMultiSelectFieldInput
defaultValue={stepFilter.value}
onChange={onChange}
options={ACTOR_SOURCE_OPTIONS}
readonly={readonly}
VariablePicker={WorkflowVariablePicker}
/>
) : subFieldName === 'workspaceMemberId' ? (
<FormSingleRecordPicker
objectNameSingulars={['workspaceMember']}
defaultValue={stepFilter.value}
onChange={onChange}
disabled={readonly}
VariablePicker={WorkflowVariablePicker}
/>
) : (
<FormTextFieldInput
defaultValue={stepFilter.value}
onChange={onChange}
VariablePicker={WorkflowVariablePicker}
readonly={readonly}
/>
)
) : (
<FormTextFieldInput
defaultValue={stepFilter.value}
@@ -43,6 +43,7 @@ const COMPOSITE_FIELD_METADATA_TYPES = [
FieldMetadataType.EMAILS,
FieldMetadataType.LINKS,
FieldMetadataType.CURRENCY,
FieldMetadataType.ACTOR,
];
const isFilterableFieldType = (
@@ -137,6 +137,14 @@ export const getStepFilterOperands = ({
return FILTER_OPERANDS_MAP.UUID;
case 'NUMERIC':
return FILTER_OPERANDS_MAP.NUMERIC;
case 'ACTOR': {
if (subFieldName === 'source') {
return FILTER_OPERANDS_MAP.SELECT;
} else if (subFieldName === 'workspaceMemberId') {
return FILTER_OPERANDS_MAP.RELATION;
}
return FILTER_OPERANDS_MAP.TEXT;
}
default:
return defaultOperands;
}