diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowEditActionFilterBodyEffect.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowEditActionFilterBodyEffect.tsx index 4b4af3778d..6905e6ef01 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowEditActionFilterBodyEffect.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowEditActionFilterBodyEffect.tsx @@ -1,19 +1,30 @@ import { useRecoilComponentFamilyState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyState'; import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; -import { type FilterSettings } from '@/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowEditActionFilter'; import { currentStepFilterGroupsComponentState } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/currentStepFilterGroupsComponentState'; import { currentStepFiltersComponentState } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/currentStepFiltersComponentState'; import { hasInitializedCurrentStepFilterGroupsComponentFamilyState } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/hasInitializedCurrentStepFilterGroupsComponentFamilyState'; import { hasInitializedCurrentStepFiltersComponentFamilyState } from '@/workflow/workflow-steps/workflow-actions/filter-action/states/hasInitializedCurrentStepFiltersComponentFamilyState'; -import { useEffect } from 'react'; -import { isDefined } from 'twenty-shared/utils'; +import { useEffect, useMemo } from 'react'; +import { + type StepFilterGroup, + type StepFilterWithPotentiallyDeprecatedOperand, +} from 'twenty-shared/types'; +import { + convertViewFilterOperandToCoreOperand, + isDefined, +} from 'twenty-shared/utils'; + +type FilterSettingsWithPotentiallyDeprecatedOperand = { + stepFilterGroups?: StepFilterGroup[]; + stepFilters?: StepFilterWithPotentiallyDeprecatedOperand[]; +}; export const WorkflowEditActionFilterBodyEffect = ({ stepId, defaultValue, }: { stepId: string; - defaultValue?: FilterSettings; + defaultValue?: FilterSettingsWithPotentiallyDeprecatedOperand; }) => { const [ hasInitializedCurrentStepFilters, @@ -39,19 +50,23 @@ export const WorkflowEditActionFilterBodyEffect = ({ currentStepFilterGroupsComponentState, ); + const stepFiltersConverted = useMemo(() => { + return defaultValue?.stepFilters?.map((filter) => ({ + ...filter, + operand: convertViewFilterOperandToCoreOperand(filter.operand), + })); + }, [defaultValue?.stepFilters]); + useEffect(() => { - if ( - !hasInitializedCurrentStepFilters && - isDefined(defaultValue?.stepFilters) - ) { - setCurrentStepFilters(defaultValue.stepFilters ?? []); + if (!hasInitializedCurrentStepFilters && isDefined(stepFiltersConverted)) { + setCurrentStepFilters(stepFiltersConverted ?? []); setHasInitializedCurrentStepFilters(true); } }, [ setCurrentStepFilters, hasInitializedCurrentStepFilters, setHasInitializedCurrentStepFilters, - defaultValue?.stepFilters, + stepFiltersConverted, ]); useEffect(() => { diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-5/1-5-migrate-views-to-core.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-5/1-5-migrate-views-to-core.command.ts index 701bf5a258..39659105b8 100644 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-5/1-5-migrate-views-to-core.command.ts +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/1-5/1-5-migrate-views-to-core.command.ts @@ -2,6 +2,7 @@ import { InjectDataSource, InjectRepository } from '@nestjs/typeorm'; import { Command } from 'nest-commander'; import { type ViewFilterOperand as SharedViewFilterOperand } from 'twenty-shared/types'; +import { convertViewFilterOperandToCoreOperand } from 'twenty-shared/utils'; import { DataSource, In, Repository, type QueryRunner } from 'typeorm'; import { type QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity'; @@ -30,7 +31,6 @@ import { type ViewFilterWorkspaceEntity } from 'src/modules/view/standard-object import { type ViewGroupWorkspaceEntity } from 'src/modules/view/standard-objects/view-group.workspace-entity'; import { type ViewSortWorkspaceEntity } from 'src/modules/view/standard-objects/view-sort.workspace-entity'; import { type ViewWorkspaceEntity } from 'src/modules/view/standard-objects/view.workspace-entity'; -import { convertViewFilterOperandToCoreOperand } from 'src/modules/view/utils/convert-view-filter-operand-to-core-operand.util'; import { convertViewFilterWorkspaceValueToCoreValue } from 'src/modules/view/utils/convert-view-filter-workspace-value-to-core-value'; @Command({ diff --git a/packages/twenty-server/src/modules/view/utils/convert-view-filter-operand-to-core-operand.util.ts b/packages/twenty-server/src/modules/view/utils/convert-view-filter-operand-to-core-operand.util.ts deleted file mode 100644 index 6985b21f8e..0000000000 --- a/packages/twenty-server/src/modules/view/utils/convert-view-filter-operand-to-core-operand.util.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { ViewFilterOperand } from 'twenty-shared/types'; - -const operandMapping: Record = { - Is: ViewFilterOperand.IS, - IsNotNull: ViewFilterOperand.IS_NOT_NULL, - IsNot: ViewFilterOperand.IS_NOT, - LessThanOrEqual: ViewFilterOperand.LESS_THAN_OR_EQUAL, - GreaterThanOrEqual: ViewFilterOperand.GREATER_THAN_OR_EQUAL, - IsBefore: ViewFilterOperand.IS_BEFORE, - IsAfter: ViewFilterOperand.IS_AFTER, - Contains: ViewFilterOperand.CONTAINS, - DoesNotContain: ViewFilterOperand.DOES_NOT_CONTAIN, - IsEmpty: ViewFilterOperand.IS_EMPTY, - IsNotEmpty: ViewFilterOperand.IS_NOT_EMPTY, - IsRelative: ViewFilterOperand.IS_RELATIVE, - IsInPast: ViewFilterOperand.IS_IN_PAST, - IsInFuture: ViewFilterOperand.IS_IN_FUTURE, - IsToday: ViewFilterOperand.IS_TODAY, - VectorSearch: ViewFilterOperand.VECTOR_SEARCH, -}; - -export const convertViewFilterOperandToCoreOperand = ( - sharedOperand: string, -): ViewFilterOperand => { - return operandMapping[sharedOperand]; -}; diff --git a/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/filter/utils/evaluate-filter-conditions.util.ts b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/filter/utils/evaluate-filter-conditions.util.ts index 84cd856768..ff7924fd78 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/filter/utils/evaluate-filter-conditions.util.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/filter/utils/evaluate-filter-conditions.util.ts @@ -8,23 +8,45 @@ import { type StepFilter, type StepFilterGroup, ViewFilterOperand, + type ViewFilterOperandDeprecated, } from 'twenty-shared/types'; +import { convertViewFilterOperandToCoreOperand as convertViewFilterOperandDeprecated } from 'twenty-shared/utils'; import { parseAndEvaluateRelativeDateFilter } from 'src/modules/workflow/workflow-executor/workflow-actions/filter/utils/parse-and-evaluate-relative-date-filter.util'; -type ResolvedFilter = Omit & { +type ResolvedFilterWithPotentiallyDeprecatedOperand = Omit< + StepFilter, + 'value' | 'stepOutputKey' | 'operand' +> & { rightOperand: unknown; leftOperand: unknown; + operand: ViewFilterOperand | ViewFilterOperandDeprecated; }; -function evaluateFilter(filter: ResolvedFilter): boolean { +type ResolvedFilter = Omit< + StepFilter, + 'value' | 'stepOutputKey' | 'operand' +> & { + rightOperand: unknown; + leftOperand: unknown; + operand: ViewFilterOperand; +}; + +function evaluateFilter( + filter: ResolvedFilterWithPotentiallyDeprecatedOperand, +): boolean { + const filterWithConvertedOperand = { + ...filter, + operand: convertViewFilterOperandDeprecated(filter.operand), + }; + switch (filter.type) { case 'NUMBER': case 'NUMERIC': - return evaluateNumberFilter(filter); + return evaluateNumberFilter(filterWithConvertedOperand); case 'DATE': case 'DATE_TIME': - return evaluateDateFilter(filter); + return evaluateDateFilter(filterWithConvertedOperand); case 'TEXT': case 'MULTI_SELECT': case 'FULL_NAME': @@ -34,19 +56,19 @@ function evaluateFilter(filter: ResolvedFilter): boolean { case 'LINKS': case 'ARRAY': case 'RAW_JSON': - return evaluateTextAndArrayFilter(filter); + return evaluateTextAndArrayFilter(filterWithConvertedOperand); case 'SELECT': - return evaluateSelectFilter(filter); + return evaluateSelectFilter(filterWithConvertedOperand); case 'BOOLEAN': - return evaluateBooleanFilter(filter); + return evaluateBooleanFilter(filterWithConvertedOperand); case 'UUID': - return evaluateUuidFilter(filter); + return evaluateUuidFilter(filterWithConvertedOperand); case 'RELATION': - return evaluateRelationFilter(filter); + return evaluateRelationFilter(filterWithConvertedOperand); case 'CURRENCY': - return evaluateCurrencyFilter(filter); + return evaluateCurrencyFilter(filterWithConvertedOperand); default: - return evaluateDefaultFilter(filter); + return evaluateDefaultFilter(filterWithConvertedOperand); } } diff --git a/packages/twenty-shared/src/types/StepFilters.ts b/packages/twenty-shared/src/types/StepFilters.ts index 145a276bc0..8bb9a918b4 100644 --- a/packages/twenty-shared/src/types/StepFilters.ts +++ b/packages/twenty-shared/src/types/StepFilters.ts @@ -1,3 +1,4 @@ +import { type ViewFilterOperandDeprecated } from '@/types/ViewFilterOperandDeprecated'; import { type ViewFilterOperand } from './ViewFilterOperand'; export enum StepLogicalOperator { @@ -24,3 +25,16 @@ export type StepFilter = { compositeFieldSubFieldName?: string; isFullRecord?: boolean; }; + +export type StepFilterWithPotentiallyDeprecatedOperand = { + id: string; + type: string; + stepOutputKey: string; + operand: ViewFilterOperand | ViewFilterOperandDeprecated; + value: string; + stepFilterGroupId: string; + positionInStepFilterGroup?: number; + fieldMetadataId?: string; + compositeFieldSubFieldName?: string; + isFullRecord?: boolean; +}; diff --git a/packages/twenty-shared/src/types/ViewFilterOperandDeprecated.ts b/packages/twenty-shared/src/types/ViewFilterOperandDeprecated.ts new file mode 100644 index 0000000000..04c38a1c21 --- /dev/null +++ b/packages/twenty-shared/src/types/ViewFilterOperandDeprecated.ts @@ -0,0 +1,19 @@ +export enum ViewFilterOperandDeprecated { + Is = 'is', + IsNotNull = 'isNotNull', + IsNot = 'isNot', + LessThanOrEqual = 'lessThanOrEqual', + GreaterThanOrEqual = 'greaterThanOrEqual', + IsBefore = 'isBefore', + IsAfter = 'isAfter', + Contains = 'contains', + DoesNotContain = 'doesNotContain', + IsEmpty = 'isEmpty', + IsNotEmpty = 'isNotEmpty', + IsRelative = 'isRelative', + IsInPast = 'isInPast', + IsInFuture = 'isInFuture', + IsToday = 'isToday', + VectorSearch = 'vectorSearch', +} + \ No newline at end of file diff --git a/packages/twenty-shared/src/types/index.ts b/packages/twenty-shared/src/types/index.ts index a45d030bce..2516e89fd3 100644 --- a/packages/twenty-shared/src/types/index.ts +++ b/packages/twenty-shared/src/types/index.ts @@ -82,7 +82,12 @@ export { DEFAULT_RELATIVE_DATE_VALUE } from './RelativeDateValue'; export type { RestrictedFieldPermissions } from './RestrictedFieldPermissions'; export type { RestrictedFieldsPermissions } from './RestrictedFieldsPermissions'; export { SettingsPath } from './SettingsPath'; -export type { StepFilterGroup, StepFilter } from './StepFilters'; +export type { + StepFilterGroup, + StepFilter, + StepFilterWithPotentiallyDeprecatedOperand, +} from './StepFilters'; export { StepLogicalOperator } from './StepFilters'; export { TwoFactorAuthenticationStrategy } from './TwoFactorAuthenticationStrategy'; export { ViewFilterOperand } from './ViewFilterOperand'; +export { ViewFilterOperandDeprecated } from './ViewFilterOperandDeprecated'; diff --git a/packages/twenty-shared/src/utils/filter/utils/convert-view-filter-operand-to-core-operand.util.ts b/packages/twenty-shared/src/utils/filter/utils/convert-view-filter-operand-to-core-operand.util.ts new file mode 100644 index 0000000000..51755bb46d --- /dev/null +++ b/packages/twenty-shared/src/utils/filter/utils/convert-view-filter-operand-to-core-operand.util.ts @@ -0,0 +1,59 @@ +import { ViewFilterOperand, ViewFilterOperandDeprecated } from '@/types'; + +const operandMapping: Record = { + Is: ViewFilterOperand.IS, + IsNotNull: ViewFilterOperand.IS_NOT_NULL, + IsNot: ViewFilterOperand.IS_NOT, + LessThanOrEqual: ViewFilterOperand.LESS_THAN_OR_EQUAL, + GreaterThanOrEqual: ViewFilterOperand.GREATER_THAN_OR_EQUAL, + IsBefore: ViewFilterOperand.IS_BEFORE, + IsAfter: ViewFilterOperand.IS_AFTER, + Contains: ViewFilterOperand.CONTAINS, + DoesNotContain: ViewFilterOperand.DOES_NOT_CONTAIN, + IsEmpty: ViewFilterOperand.IS_EMPTY, + IsNotEmpty: ViewFilterOperand.IS_NOT_EMPTY, + IsRelative: ViewFilterOperand.IS_RELATIVE, + IsInPast: ViewFilterOperand.IS_IN_PAST, + IsInFuture: ViewFilterOperand.IS_IN_FUTURE, + IsToday: ViewFilterOperand.IS_TODAY, + VectorSearch: ViewFilterOperand.VECTOR_SEARCH, + [ViewFilterOperandDeprecated.Is]: ViewFilterOperand.IS, + [ViewFilterOperandDeprecated.IsNotNull]: ViewFilterOperand.IS_NOT_NULL, + [ViewFilterOperandDeprecated.IsNot]: ViewFilterOperand.IS_NOT, + [ViewFilterOperandDeprecated.LessThanOrEqual]: ViewFilterOperand.LESS_THAN_OR_EQUAL, + [ViewFilterOperandDeprecated.GreaterThanOrEqual]: ViewFilterOperand.GREATER_THAN_OR_EQUAL, + [ViewFilterOperandDeprecated.IsBefore]: ViewFilterOperand.IS_BEFORE, + [ViewFilterOperandDeprecated.IsAfter]: ViewFilterOperand.IS_AFTER, + [ViewFilterOperandDeprecated.Contains]: ViewFilterOperand.CONTAINS, + [ViewFilterOperandDeprecated.DoesNotContain]: ViewFilterOperand.DOES_NOT_CONTAIN, + [ViewFilterOperandDeprecated.IsEmpty]: ViewFilterOperand.IS_EMPTY, + [ViewFilterOperandDeprecated.IsNotEmpty]: ViewFilterOperand.IS_NOT_EMPTY, + [ViewFilterOperandDeprecated.IsRelative]: ViewFilterOperand.IS_RELATIVE, + [ViewFilterOperandDeprecated.IsInPast]: ViewFilterOperand.IS_IN_PAST, + [ViewFilterOperandDeprecated.IsInFuture]: ViewFilterOperand.IS_IN_FUTURE, + [ViewFilterOperandDeprecated.IsToday]: ViewFilterOperand.IS_TODAY, + [ViewFilterOperandDeprecated.VectorSearch]: ViewFilterOperand.VECTOR_SEARCH, + [ViewFilterOperand.IS]: ViewFilterOperand.IS, + [ViewFilterOperand.IS_NOT_NULL]: ViewFilterOperand.IS_NOT_NULL, + [ViewFilterOperand.IS_NOT]: ViewFilterOperand.IS_NOT, + [ViewFilterOperand.LESS_THAN_OR_EQUAL]: ViewFilterOperand.LESS_THAN_OR_EQUAL, + [ViewFilterOperand.GREATER_THAN_OR_EQUAL]: + ViewFilterOperand.GREATER_THAN_OR_EQUAL, + [ViewFilterOperand.IS_BEFORE]: ViewFilterOperand.IS_BEFORE, + [ViewFilterOperand.IS_AFTER]: ViewFilterOperand.IS_AFTER, + [ViewFilterOperand.CONTAINS]: ViewFilterOperand.CONTAINS, + [ViewFilterOperand.DOES_NOT_CONTAIN]: ViewFilterOperand.DOES_NOT_CONTAIN, + [ViewFilterOperand.IS_EMPTY]: ViewFilterOperand.IS_EMPTY, + [ViewFilterOperand.IS_NOT_EMPTY]: ViewFilterOperand.IS_NOT_EMPTY, + [ViewFilterOperand.IS_RELATIVE]: ViewFilterOperand.IS_RELATIVE, + [ViewFilterOperand.IS_IN_PAST]: ViewFilterOperand.IS_IN_PAST, + [ViewFilterOperand.IS_IN_FUTURE]: ViewFilterOperand.IS_IN_FUTURE, + [ViewFilterOperand.IS_TODAY]: ViewFilterOperand.IS_TODAY, + [ViewFilterOperand.VECTOR_SEARCH]: ViewFilterOperand.VECTOR_SEARCH, +}; + +export const convertViewFilterOperandToCoreOperand = ( + sharedOperand: string, +): ViewFilterOperand => { + return operandMapping[sharedOperand]; +}; diff --git a/packages/twenty-shared/src/utils/index.ts b/packages/twenty-shared/src/utils/index.ts index 0e5d49165f..33b5860f68 100644 --- a/packages/twenty-shared/src/utils/index.ts +++ b/packages/twenty-shared/src/utils/index.ts @@ -36,6 +36,7 @@ export type { export { turnRecordFilterGroupsIntoGqlOperationFilter } from './filter/turnRecordFilterGroupIntoGqlOperationFilter'; export { turnRecordFilterIntoRecordGqlOperationFilter } from './filter/turnRecordFilterIntoGqlOperationFilter'; export { combineFilters } from './filter/utils/combineFilters'; +export { convertViewFilterOperandToCoreOperand } from './filter/utils/convert-view-filter-operand-to-core-operand.util'; export { convertViewFilterValueToString } from './filter/utils/convertViewFilterValueToString'; export { createAnyFieldRecordFilterBaseProperties } from './filter/utils/createAnyFieldRecordFilterBaseProperties'; export { diff --git a/packages/twenty-shared/src/workflow/schemas/filter-action-settings-schema.ts b/packages/twenty-shared/src/workflow/schemas/filter-action-settings-schema.ts index 4393a9a6bc..4c7da8b800 100644 --- a/packages/twenty-shared/src/workflow/schemas/filter-action-settings-schema.ts +++ b/packages/twenty-shared/src/workflow/schemas/filter-action-settings-schema.ts @@ -1,3 +1,4 @@ +import { ViewFilterOperandDeprecated } from '@/types'; import { z } from 'zod'; import { StepLogicalOperator } from '../../types/StepFilters'; import { ViewFilterOperand } from '../../types/ViewFilterOperand'; @@ -19,7 +20,7 @@ export const workflowFilterActionSettingsSchema = id: z.string(), type: z.string(), stepOutputKey: z.string(), - operand: z.enum(ViewFilterOperand), + operand: z.enum(ViewFilterOperand).or(z.enum(ViewFilterOperandDeprecated)), value: z.string(), stepFilterGroupId: z.string(), positionInStepFilterGroup: z.number().optional(),