From a2827494a1446453dd3207b7f173fb3699f31bdf Mon Sep 17 00:00:00 2001 From: Thomas Trompette Date: Tue, 30 Dec 2025 10:34:08 +0100 Subject: [PATCH] Support actor filtering in workflows (#16783) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes https://github.com/twentyhq/twenty/issues/15782 Find records Capture d’écran 2025-12-23 à 16 23
49 Filters Capture d’écran 2025-12-23 à 16 23
32 --- > [!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 > > 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). --------- Co-authored-by: Félix Malfait --- ...ommandMenuValueFormCompositeFieldInput.tsx | 26 ++++++++++++++ .../AdvancedFilterFieldSelectMenu.tsx | 19 ++-------- .../components/FormSingleRecordPicker.tsx | 2 +- .../WorkflowStepFilterFieldSelect.tsx | 1 - .../WorkflowStepFilterValueCompositeInput.tsx | 36 ++++++++++++++++++- .../WorkflowStepFilterValueInput.tsx | 1 + .../utils/getStepFilterOperands.ts | 8 +++++ .../utils/evaluate-filter-conditions.util.ts | 16 +++++++++ 8 files changed, 90 insertions(+), 19 deletions(-) diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/command-menu/components/AdvancedFilterCommandMenuValueFormCompositeFieldInput.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/command-menu/components/AdvancedFilterCommandMenuValueFormCompositeFieldInput.tsx index 01f987a7e4..807d3ded95 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/command-menu/components/AdvancedFilterCommandMenuValueFormCompositeFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/command-menu/components/AdvancedFilterCommandMenuValueFormCompositeFieldInput.tsx @@ -8,8 +8,17 @@ import { type RecordFilter } from '@/object-record/record-filter/types/RecordFil import { CURRENCIES } from '@/settings/data-model/constants/Currencies'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { useContext } from 'react'; +import { FieldActorSource } 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 AdvancedFilterCommandMenuValueFormCompositeFieldInput = ({ recordFilter, onChange, @@ -78,6 +87,23 @@ export const AdvancedFilterCommandMenuValueFormCompositeFieldInput = ({ readonly={readonly} /> ) + ) : filterType === 'ACTOR' ? ( + recordFilter.subFieldName === 'source' ? ( + + ) : ( + + ) ) : ( - shouldDisplayFormField({ - fieldMetadataItem, - actionType: 'FIND_RECORDS', - }), - ) - : filterableFieldMetadataItemsForRecordIndex; + const { filterableFieldMetadataItems: filterableFieldMetadataItems } = + useFilterableFieldMetadataItems(objectMetadataItem.id); const visibleRecordFields = useRecoilComponentValue( visibleRecordFieldsComponentSelector, diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormSingleRecordPicker.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormSingleRecordPicker.tsx index 826bf0a200..d27e0a66ec 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormSingleRecordPicker.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormSingleRecordPicker.tsx @@ -1,4 +1,3 @@ -import { t } from '@lingui/core/macro'; import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord'; import { FormFieldInputContainer } from '@/object-record/record-field/ui/form-types/components/FormFieldInputContainer'; import { FormFieldInputInnerContainer } from '@/object-record/record-field/ui/form-types/components/FormFieldInputInnerContainer'; @@ -17,6 +16,7 @@ import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state import { isStandaloneVariableString } from '@/workflow/utils/isStandaloneVariableString'; import { css, useTheme } from '@emotion/react'; import styled from '@emotion/styled'; +import { t } from '@lingui/core/macro'; import { isNonEmptyString } from '@sniptt/guards'; import { useCallback, useId } from 'react'; import { CustomError, isDefined, isValidUuid } from 'twenty-shared/utils'; diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowStepFilterFieldSelect.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowStepFilterFieldSelect.tsx index 7b7f3017ad..7ef4aa4fbe 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowStepFilterFieldSelect.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowStepFilterFieldSelect.tsx @@ -23,7 +23,6 @@ type WorkflowStepFilterFieldSelectProps = { }; const NON_SELECTABLE_FIELD_TYPES = [ - FieldMetadataType.ACTOR, FieldMetadataType.RICH_TEXT_V2, FieldMetadataType.RATING, ]; diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowStepFilterValueCompositeInput.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowStepFilterValueCompositeInput.tsx index 5d07344686..33e7c2c151 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowStepFilterValueCompositeInput.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowStepFilterValueCompositeInput.tsx @@ -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' ? ( + + ) : subFieldName === 'workspaceMemberId' ? ( + + ) : ( + + ) ) : (