diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterDropdownColumn.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterDropdownColumn.tsx new file mode 100644 index 000000000..9970de5d2 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterDropdownColumn.tsx @@ -0,0 +1,10 @@ +import styled from '@emotion/styled'; + +const StyledColumn = styled.div` + display: flex; + flex-direction: column; + width: 100%; + gap: ${({ theme }) => theme.spacing(1)}; +`; + +export const AdvancedFilterDropdownColumn = StyledColumn; diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterLogicalOperatorCell.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterLogicalOperatorCell.tsx index 8470671a3..0365885d2 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterLogicalOperatorCell.tsx +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterLogicalOperatorCell.tsx @@ -1,15 +1,18 @@ import { AdvancedFilterLogicalOperatorDropdown } from '@/object-record/advanced-filter/components/AdvancedFilterLogicalOperatorDropdown'; +import { AdvancedFilterContext } from '@/object-record/advanced-filter/states/context/AdvancedFilterContext'; import { RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup'; import styled from '@emotion/styled'; +import { useContext } from 'react'; import { capitalize } from 'twenty-shared/utils'; -const StyledText = styled.div` +const StyledText = styled.div<{ noPadding?: boolean }>` height: ${({ theme }) => theme.spacing(8)}; display: flex; align-items: center; - padding-left: ${({ theme }) => theme.spacing(2.25)}; + padding-left: ${({ theme, noPadding }) => + noPadding ? 0 : theme.spacing(2.25)}; `; const StyledContainer = styled.div` @@ -27,18 +30,22 @@ type AdvancedFilterLogicalOperatorCellProps = { export const AdvancedFilterLogicalOperatorCell = ({ index, recordFilterGroup, -}: AdvancedFilterLogicalOperatorCellProps) => ( - - {index === 0 ? ( - Where - ) : index === 1 ? ( - - ) : ( - - {capitalize(recordFilterGroup.logicalOperator.toLowerCase())} - - )} - -); +}: AdvancedFilterLogicalOperatorCellProps) => { + const { isColumn } = useContext(AdvancedFilterContext); + + return ( + + {index === 0 ? ( + Where + ) : index === 1 ? ( + + ) : ( + + {capitalize(recordFilterGroup.logicalOperator.toLowerCase())} + + )} + + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilter.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilter.tsx new file mode 100644 index 000000000..3f39e08fd --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilter.tsx @@ -0,0 +1,36 @@ +import { AdvancedFilterRecordFilterColumn } from '@/object-record/advanced-filter/components/AdvancedFilterRecordFilterColumn'; +import { AdvancedFilterRecordFilterRow } from '@/object-record/advanced-filter/components/AdvancedFilterRecordFilterRow'; +import { AdvancedFilterContext } from '@/object-record/advanced-filter/states/context/AdvancedFilterContext'; +import { VariablePickerComponent } from '@/object-record/record-field/form-types/types/VariablePickerComponent'; +import { RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup'; +import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; +import { useContext } from 'react'; + +export const AdvancedFilterRecordFilter = ({ + recordFilterGroup, + recordFilter, + recordFilterIndex, + VariablePicker, +}: { + recordFilterGroup: RecordFilterGroup; + recordFilter: RecordFilter; + recordFilterIndex: number; + VariablePicker?: VariablePickerComponent; +}) => { + const { isColumn } = useContext(AdvancedFilterContext); + + return isColumn ? ( + + ) : ( + + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilterColumn.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilterColumn.tsx new file mode 100644 index 000000000..3e7128d09 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilterColumn.tsx @@ -0,0 +1,63 @@ +import { AdvancedFilterDropdownColumn } from '@/object-record/advanced-filter/components/AdvancedFilterDropdownColumn'; +import { AdvancedFilterFieldSelectDropdownButton } from '@/object-record/advanced-filter/components/AdvancedFilterFieldSelectDropdownButton'; +import { AdvancedFilterLogicalOperatorCell } from '@/object-record/advanced-filter/components/AdvancedFilterLogicalOperatorCell'; +import { AdvancedFilterRecordFilterOperandSelect } from '@/object-record/advanced-filter/components/AdvancedFilterRecordFilterOperandSelect'; +import { AdvancedFilterRecordFilterOptionsDropdown } from '@/object-record/advanced-filter/components/AdvancedFilterRecordFilterOptionsDropdown'; +import { AdvancedFilterValueFormInput } from '@/object-record/advanced-filter/components/AdvancedFilterValueFormInput'; +import { getAdvancedFilterObjectFilterDropdownComponentInstanceId } from '@/object-record/advanced-filter/utils/getAdvancedFilterObjectFilterDropdownComponentInstanceId'; +import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext'; +import { VariablePickerComponent } from '@/object-record/record-field/form-types/types/VariablePickerComponent'; +import { RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup'; +import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; +import styled from '@emotion/styled'; + +const StyledContainer = styled.div` + display: flex; + flex-direction: row; + justify-content: space-between; + gap: ${({ theme }) => theme.spacing(1)}; +`; + +export const AdvancedFilterRecordFilterColumn = ({ + recordFilterGroup, + recordFilter, + recordFilterIndex, + VariablePicker, +}: { + recordFilterGroup: RecordFilterGroup; + recordFilter: RecordFilter; + recordFilterIndex: number; + VariablePicker?: VariablePickerComponent; +}) => { + return ( + + + + + + + + + + + + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilterGroup.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilterGroup.tsx new file mode 100644 index 000000000..972879509 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilterGroup.tsx @@ -0,0 +1,36 @@ +import { AdvancedFilterRecordFilterGroupColumn } from '@/object-record/advanced-filter/components/AdvancedFilterRecordFilterGroupColumn'; +import { AdvancedFilterRecordFilterGroupRow } from '@/object-record/advanced-filter/components/AdvancedFilterRecordFilterGroupRow'; +import { AdvancedFilterContext } from '@/object-record/advanced-filter/states/context/AdvancedFilterContext'; +import { VariablePickerComponent } from '@/object-record/record-field/form-types/types/VariablePickerComponent'; +import { RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup'; +import { useContext } from 'react'; + +export const AdvancedFilterRecordFilterGroup = ({ + parentRecordFilterGroup, + recordFilterGroup, + recordFilterGroupIndex, + VariablePicker, +}: { + parentRecordFilterGroup: RecordFilterGroup; + recordFilterGroup: RecordFilterGroup; + recordFilterGroupIndex: number; + VariablePicker?: VariablePickerComponent; +}) => { + const { isColumn } = useContext(AdvancedFilterContext); + + return isColumn ? ( + + ) : ( + + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilterGroupChildren.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilterGroupChildren.tsx index 291181b9f..58f49956a 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilterGroupChildren.tsx +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilterGroupChildren.tsx @@ -1,5 +1,5 @@ import { AdvancedFilterAddFilterRuleSelect } from '@/object-record/advanced-filter/components/AdvancedFilterAddFilterRuleSelect'; -import { AdvancedFilterRecordFilterRow } from '@/object-record/advanced-filter/components/AdvancedFilterRecordFilterRow'; +import { AdvancedFilterRecordFilter } from '@/object-record/advanced-filter/components/AdvancedFilterRecordFilter'; import { useChildRecordFiltersAndRecordFilterGroups } from '@/object-record/advanced-filter/hooks/useChildRecordFiltersAndRecordFilterGroups'; import { VariablePickerComponent } from '@/object-record/record-field/form-types/types/VariablePickerComponent'; @@ -45,7 +45,7 @@ export const AdvancedFilterRecordFilterGroupChildren = ({ return ( {childRecordFilters.map((childRecordFilter, childRecordFilterIndex) => ( - theme.spacing(1)}; +`; + +export const AdvancedFilterRecordFilterGroupColumn = ({ + parentRecordFilterGroup, + recordFilterGroup, + recordFilterGroupIndex, + VariablePicker, +}: { + parentRecordFilterGroup: RecordFilterGroup; + recordFilterGroup: RecordFilterGroup; + recordFilterGroupIndex: number; + VariablePicker?: VariablePickerComponent; +}) => { + return ( + + + + + + + + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilterOperandSelect.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilterOperandSelect.tsx index 537730b90..730796564 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilterOperandSelect.tsx +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilterOperandSelect.tsx @@ -1,4 +1,5 @@ import { DEFAULT_ADVANCED_FILTER_DROPDOWN_OFFSET } from '@/object-record/advanced-filter/constants/DefaultAdvancedFilterDropdownOffset'; +import { AdvancedFilterContext } from '@/object-record/advanced-filter/states/context/AdvancedFilterContext'; import { useApplyObjectFilterDropdownOperand } from '@/object-record/object-filter-dropdown/hooks/useApplyObjectFilterDropdownOperand'; import { getOperandLabel } from '@/object-record/object-filter-dropdown/utils/getOperandLabel'; @@ -16,11 +17,12 @@ import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { ViewFilterOperand } from '@/views/types/ViewFilterOperand'; import styled from '@emotion/styled'; +import { useContext } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { MenuItem } from 'twenty-ui/navigation'; -const StyledContainer = styled.div` - width: 100px; +const StyledContainer = styled.div<{ isColumn?: boolean }>` + width: ${({ isColumn }) => (isColumn ? 'auto' : '100px')}; `; type AdvancedFilterRecordFilterOperandSelectProps = { @@ -36,6 +38,8 @@ export const AdvancedFilterRecordFilterOperandSelect = ({ currentRecordFiltersComponentState, ); + const { isColumn } = useContext(AdvancedFilterContext); + const filter = currentRecordFilters.find( (recordFilter) => recordFilter.id === recordFilterId, ); @@ -82,7 +86,7 @@ export const AdvancedFilterRecordFilterOperandSelect = ({ } return ( - + { return ( + - {isDefined(VariablePicker) ? ( - - ) : ( - - )} + diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRootRecordFilterGroup.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRootRecordFilterGroup.tsx index a8a31d601..36031cac6 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRootRecordFilterGroup.tsx +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRootRecordFilterGroup.tsx @@ -1,7 +1,7 @@ import { AdvancedFilterAddFilterRuleSelect } from '@/object-record/advanced-filter/components/AdvancedFilterAddFilterRuleSelect'; +import { AdvancedFilterRecordFilter } from '@/object-record/advanced-filter/components/AdvancedFilterRecordFilter'; +import { AdvancedFilterRecordFilterGroup } from '@/object-record/advanced-filter/components/AdvancedFilterRecordFilterGroup'; -import { AdvancedFilterRecordFilterGroupRow } from '@/object-record/advanced-filter/components/AdvancedFilterRecordFilterGroupRow'; -import { AdvancedFilterRecordFilterRow } from '@/object-record/advanced-filter/components/AdvancedFilterRecordFilterRow'; import { ADVANCED_FILTER_DROPDOWN_CONTENT_WIDTH } from '@/object-record/advanced-filter/constants/AdvancedFilterDropdownContentWidth'; import { useChildRecordFiltersAndRecordFilterGroups } from '@/object-record/advanced-filter/hooks/useChildRecordFiltersAndRecordFilterGroups'; import { rootLevelRecordFilterGroupComponentSelector } from '@/object-record/advanced-filter/states/rootLevelRecordFilterGroupComponentSelector'; @@ -45,14 +45,14 @@ export const AdvancedFilterRootRecordFilterGroup = () => { isRecordFilterGroupChildARecordFilterGroup( recordFilterGroupChild, ) ? ( - ) : ( - void; + VariablePicker?: VariablePickerComponent; }) => { const subFieldNameUsedInDropdown = useRecoilComponentValueV2( subFieldNameUsedInDropdownComponentState, @@ -25,8 +25,8 @@ export const AdvancedFilterValueFormCompositeFieldInput = ({ return ( <> - {filterType === 'ADDRESS' && - (subFieldNameUsedInDropdown === 'addressCountry' ? ( + {filterType === 'ADDRESS' ? ( + subFieldNameUsedInDropdown === 'addressCountry' ? ( - ))} - {filterType === 'CURRENCY' && - (recordFilter.subFieldName === 'currencyCode' ? ( + ) + ) : filterType === 'CURRENCY' ? ( + recordFilter.subFieldName === 'currencyCode' ? ( - ) : null)} + ) : null + ) : filterType === 'PHONES' ? ( + recordFilter.subFieldName === 'primaryPhoneNumber' ? ( + + ) : ( + + ) + ) : ( + + )} ); }; diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterValueFormInput.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterValueFormInput.tsx index bbd0f9e81..69cbdb3ce 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterValueFormInput.tsx +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterValueFormInput.tsx @@ -1,10 +1,13 @@ +import { formatFieldMetadataItemAsFieldDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsFieldDefinition'; import { AdvancedFilterValueFormCompositeFieldInput } from '@/object-record/advanced-filter/components/AdvancedFilterValueFormCompositeFieldInput'; import { useApplyObjectFilterDropdownFilterValue } from '@/object-record/object-filter-dropdown/hooks/useApplyObjectFilterDropdownFilterValue'; +import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector'; import { subFieldNameUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/subFieldNameUsedInDropdownComponentState'; import { FormFieldInput } from '@/object-record/record-field/components/FormFieldInput'; import { VariablePickerComponent } from '@/object-record/record-field/form-types/types/VariablePickerComponent'; import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata'; import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; +import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { FieldMetadataType } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; @@ -15,12 +18,14 @@ export const AdvancedFilterValueFormInput = ({ VariablePicker, }: { recordFilterId: string; - VariablePicker: VariablePickerComponent; + VariablePicker?: VariablePickerComponent; }) => { const currentRecordFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, ); + const { objectMetadataItem } = useRecordIndexContextOrThrow(); + const subFieldNameUsedInDropdown = useRecoilComponentValueV2( subFieldNameUsedInDropdownComponentState, ); @@ -35,9 +40,20 @@ export const AdvancedFilterValueFormInput = ({ useApplyObjectFilterDropdownFilterValue(); const handleChange = (newValue: JsonValue) => { - applyObjectFilterDropdownFilterValue(newValue as string); + applyObjectFilterDropdownFilterValue(String(newValue)); }; + const fieldMetadataItemUsedInDropdown = useRecoilComponentValueV2( + fieldMetadataItemUsedInDropdownComponentSelector, + ); + + const fieldDefinition = fieldMetadataItemUsedInDropdown + ? formatFieldMetadataItemAsFieldDefinition({ + field: fieldMetadataItemUsedInDropdown, + objectMetadataItem: objectMetadataItem, + }) + : null; + if (isDisabled) { return null; } @@ -57,7 +73,7 @@ export const AdvancedFilterValueFormInput = ({ field={{ type: recordFilter.type as FieldMetadataType, label: '', - metadata: {} as FieldMetadata, + metadata: fieldDefinition?.metadata as FieldMetadata, }} defaultValue={recordFilter.value} onChange={handleChange} diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/hooks/useDefaultFieldMetadataItemForFilter.ts b/packages/twenty-front/src/modules/object-record/advanced-filter/hooks/useDefaultFieldMetadataItemForFilter.ts index dc6d7017a..dd67718b7 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/hooks/useDefaultFieldMetadataItemForFilter.ts +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/hooks/useDefaultFieldMetadataItemForFilter.ts @@ -1,3 +1,4 @@ +import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems'; import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById'; import { availableFieldMetadataItemsForFilterFamilySelector } from '@/object-metadata/states/availableFieldMetadataItemsForFilterFamilySelector'; import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; @@ -7,11 +8,13 @@ import { isDefined } from 'twenty-shared/utils'; export const useDefaultFieldMetadataItemForFilter = () => { const { currentView } = useGetCurrentViewOnly(); + const { activeObjectMetadataItems } = useFilteredObjectMetadataItems(); - const objectMetadataId = currentView?.objectMetadataId; + const objectMetadataId = + currentView?.objectMetadataId ?? activeObjectMetadataItems[0]?.id; if (!isDefined(objectMetadataId)) { - throw new Error('Object metadata id is missing from current view'); + throw new Error('Could not find default object metadata item for filter'); } const { objectMetadataItem } = useObjectMetadataItemById({ diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/states/context/AdvancedFilterContext.ts b/packages/twenty-front/src/modules/object-record/advanced-filter/states/context/AdvancedFilterContext.ts index 000feb023..21cae4c93 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/states/context/AdvancedFilterContext.ts +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/states/context/AdvancedFilterContext.ts @@ -2,6 +2,7 @@ import { createContext } from 'react'; type AdvancedFilterContextType = { onUpdate?: () => void; + isColumn?: boolean; }; export const AdvancedFilterContext = createContext( diff --git a/packages/twenty-front/src/modules/object-record/record-field/components/FormFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/components/FormFieldInput.tsx index 729a8f68d..a60e04872 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/components/FormFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/components/FormFieldInput.tsx @@ -10,11 +10,11 @@ import { FormMultiSelectFieldInput } from '@/object-record/record-field/form-typ import { FormNumberFieldInput } from '@/object-record/record-field/form-types/components/FormNumberFieldInput'; import { FormPhoneFieldInput } from '@/object-record/record-field/form-types/components/FormPhoneFieldInput'; import { FormRawJsonFieldInput } from '@/object-record/record-field/form-types/components/FormRawJsonFieldInput'; +import { FormRelationToOneFieldInput } from '@/object-record/record-field/form-types/components/FormRelationToOneFieldInput'; import { FormRichTextV2FieldInput } from '@/object-record/record-field/form-types/components/FormRichTextV2FieldInput'; import { FormSelectFieldInput } from '@/object-record/record-field/form-types/components/FormSelectFieldInput'; import { FormTextFieldInput } from '@/object-record/record-field/form-types/components/FormTextFieldInput'; import { FormUuidFieldInput } from '@/object-record/record-field/form-types/components/FormUuidFieldInput'; -import { FormRelationToOneFieldInput } from '@/object-record/record-field/form-types/components/FormRelationToOneFieldInput'; import { VariablePickerComponent } from '@/object-record/record-field/form-types/types/VariablePickerComponent'; import { FieldDefinition } from '@/object-record/record-field/types/FieldDefinition'; import { @@ -42,11 +42,11 @@ import { isFieldMultiSelect } from '@/object-record/record-field/types/guards/is import { isFieldNumber } from '@/object-record/record-field/types/guards/isFieldNumber'; import { isFieldPhones } from '@/object-record/record-field/types/guards/isFieldPhones'; import { isFieldRawJson } from '@/object-record/record-field/types/guards/isFieldRawJson'; +import { isFieldRelationToOneObject } from '@/object-record/record-field/types/guards/isFieldRelationToOneObject'; import { isFieldRichTextV2 } from '@/object-record/record-field/types/guards/isFieldRichTextV2'; import { isFieldSelect } from '@/object-record/record-field/types/guards/isFieldSelect'; import { isFieldText } from '@/object-record/record-field/types/guards/isFieldText'; import { isFieldUuid } from '@/object-record/record-field/types/guards/isFieldUuid'; -import { isFieldRelationToOneObject } from '@/object-record/record-field/types/guards/isFieldRelationToOneObject'; import { JsonValue } from 'type-fest'; type FormFieldInputProps = { diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowRunStepNodeDetail.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowRunStepNodeDetail.tsx index 427fd8fef..693a6ca03 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowRunStepNodeDetail.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowRunStepNodeDetail.tsx @@ -5,9 +5,9 @@ import { WorkflowDiagramRunStatus } from '@/workflow/workflow-diagram/types/Work import { WorkflowActionServerlessFunction } from '@/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowActionServerlessFunction'; import { WorkflowEditActionCreateRecord } from '@/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionCreateRecord'; import { WorkflowEditActionDeleteRecord } from '@/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionDeleteRecord'; -import { WorkflowEditActionFindRecords } from '@/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionFindRecords'; import { WorkflowEditActionSendEmail } from '@/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionSendEmail'; import { WorkflowEditActionUpdateRecord } from '@/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionUpdateRecord'; +import { WorkflowEditActionFindRecords } from '@/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowEditActionFindRecords'; import { WorkflowEditActionFormFiller } from '@/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowEditActionFormFiller'; import { WorkflowEditTriggerCronForm } from '@/workflow/workflow-trigger/components/WorkflowEditTriggerCronForm'; import { WorkflowEditTriggerDatabaseEventForm } from '@/workflow/workflow-trigger/components/WorkflowEditTriggerDatabaseEventForm'; diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowStepDetail.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowStepDetail.tsx index 795c59f58..37326175b 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowStepDetail.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowStepDetail.tsx @@ -4,9 +4,9 @@ import { getStepDefinitionOrThrow } from '@/workflow/utils/getStepDefinitionOrTh import { WorkflowActionServerlessFunction } from '@/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowActionServerlessFunction'; import { WorkflowEditActionCreateRecord } from '@/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionCreateRecord'; import { WorkflowEditActionDeleteRecord } from '@/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionDeleteRecord'; -import { WorkflowEditActionFindRecords } from '@/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionFindRecords'; import { WorkflowEditActionSendEmail } from '@/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionSendEmail'; import { WorkflowEditActionUpdateRecord } from '@/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionUpdateRecord'; +import { WorkflowEditActionFindRecords } from '@/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowEditActionFindRecords'; import { WorkflowEditActionFormBuilder } from '@/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowEditActionFormBuilder'; import { WorkflowEditTriggerCronForm } from '@/workflow/workflow-trigger/components/WorkflowEditTriggerCronForm'; import { WorkflowEditTriggerDatabaseEventForm } from '@/workflow/workflow-trigger/components/WorkflowEditTriggerDatabaseEventForm'; diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/__stories__/WorkflowEditActionFindRecords.stories.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/__stories__/WorkflowEditActionFindRecords.stories.tsx index 07f1cf398..704ebbb94 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/__stories__/WorkflowEditActionFindRecords.stories.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/__stories__/WorkflowEditActionFindRecords.stories.tsx @@ -1,7 +1,8 @@ import { WorkflowFindRecordsAction } from '@/workflow/types/Workflow'; -import { WorkflowEditActionFindRecords } from '@/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionFindRecords'; +import { WorkflowEditActionFindRecords } from '@/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowEditActionFindRecords'; import { Meta, StoryObj } from '@storybook/react'; import { expect, fn, userEvent, within } from '@storybook/test'; +import { ComponentDecorator, RouterDecorator } from 'twenty-ui/testing'; import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator'; import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator'; import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator'; @@ -10,7 +11,6 @@ import { WorkflowStepDecorator } from '~/testing/decorators/WorkflowStepDecorato import { WorkspaceDecorator } from '~/testing/decorators/WorkspaceDecorator'; import { graphqlMocks } from '~/testing/graphqlMocks'; import { getWorkflowNodeIdMock } from '~/testing/mock-data/workflow'; -import { ComponentDecorator, RouterDecorator } from 'twenty-ui/testing'; const DEFAULT_ACTION = { id: getWorkflowNodeIdMock(), diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/constants/RecordActions.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/constants/RecordActions.ts index 2d27e9761..37c374a39 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/constants/RecordActions.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/constants/RecordActions.ts @@ -23,10 +23,9 @@ export const RECORD_ACTIONS: Array<{ type: 'DELETE_RECORD', icon: 'IconTrash', }, - // TODO: Add search records action - // { - // label: 'Search Records', - // type: 'FIND_RECORDS', - // icon: 'IconSearch', - // }, + { + label: 'Search Records', + type: 'FIND_RECORDS', + icon: 'IconSearch', + }, ]; diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionFindRecords.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowEditActionFindRecords.tsx similarity index 74% rename from packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionFindRecords.tsx rename to packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowEditActionFindRecords.tsx index fe03c0245..421b22257 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionFindRecords.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowEditActionFindRecords.tsx @@ -11,12 +11,14 @@ import { RecordFilterGroup } from '@/object-record/record-filter-group/types/Rec import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext'; import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; import { RecordIndexContextProvider } from '@/object-record/record-index/contexts/RecordIndexContext'; +import { InputLabel } from '@/ui/input/components/InputLabel'; import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody'; -import { WorkflowFindRecordFilters } from '@/workflow/workflow-steps/workflow-actions/components/WorkflowFindRecordFilters'; -import { WorkflowFindRecordFiltersEffect } from '@/workflow/workflow-steps/workflow-actions/components/WorkflowFindRecordFiltersEffect'; +import { WorkflowFindRecordsFilters } from '@/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowFindRecordsFilters'; +import { WorkflowFindRecordsFiltersEffect } from '@/workflow/workflow-steps/workflow-actions/find-records-action/components/WorkflowFindRecordsFiltersEffect'; import { useActionHeaderTypeOrThrow } from '@/workflow/workflow-steps/workflow-actions/hooks/useActionHeaderTypeOrThrow'; import { useActionIconColorOrThrow } from '@/workflow/workflow-steps/workflow-actions/hooks/useActionIconColorOrThrow'; import { getActionIcon } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIcon'; +import { useLingui } from '@lingui/react/macro'; import { isDefined } from 'twenty-shared/utils'; import { HorizontalSeparator, useIcons } from 'twenty-ui/display'; import { SelectOption } from 'twenty-ui/input'; @@ -52,6 +54,7 @@ export const WorkflowEditActionFindRecords = ({ actionOptions, }: WorkflowEditActionFindRecordsProps) => { const { getIcon } = useIcons(); + const { t } = useLingui(); const { activeNonSystemObjectMetadataItems } = useFilteredObjectMetadataItems(); @@ -116,7 +119,7 @@ export const WorkflowEditActionFindRecords = ({ const headerIcon = getActionIcon(action.type); const headerIconColor = useActionIconColorOrThrow(action.type); const headerType = useActionHeaderTypeOrThrow(action.type); - const instanceId = `workflow-edit-action-record-find-records-${action.id}`; + const instanceId = `workflow-edit-action-record-find-records-${action.id}-${formData.objectName}`; return ( <> @@ -161,42 +164,45 @@ export const WorkflowEditActionFindRecords = ({ {isDefined(selectedObjectMetadataItem) && ( - '', - onIndexRecordsLoaded: () => {}, - objectNamePlural: selectedObjectMetadataItem.labelPlural, - objectNameSingular: selectedObjectMetadataItem.nameSingular, - objectMetadataItem: selectedObjectMetadataItem, - recordIndexId: instanceId, - objectPermissionsByObjectMetadataId, - }} - > - + {t`Conditions`} + '', + onIndexRecordsLoaded: () => {}, + objectNamePlural: selectedObjectMetadataItem.labelPlural, + objectNameSingular: selectedObjectMetadataItem.nameSingular, + objectMetadataItem: selectedObjectMetadataItem, + recordIndexId: instanceId, + objectPermissionsByObjectMetadataId, + }} > - - { - const newFormData: FindRecordsFormData = { - ...formData, - filter, - }; + + { + const newFormData: FindRecordsFormData = { + ...formData, + filter, + }; - setFormData(newFormData); + setFormData(newFormData); - saveAction(newFormData); - }} - /> - - - - + saveAction(newFormData); + }} + /> + + + + + )} { + const rootRecordFilterGroup = useRecoilComponentValueV2( + rootLevelRecordFilterGroupComponentSelector, + ); + + const { upsertRecordFilterGroup } = useUpsertRecordFilterGroup(); + + const { upsertRecordFilter } = useUpsertRecordFilter(); + + const { createEmptyRecordFilterFromFieldMetadataItem } = + useCreateEmptyRecordFilterFromFieldMetadataItem(); + + const setHasInitializedCurrentRecordFilters = + useSetRecoilComponentFamilyStateV2( + hasInitializedCurrentRecordFiltersComponentFamilyState, + {}, + ); + + const addRootRecordFilterGroup = () => { + const alreadyHasAdvancedFilterGroup = isDefined(rootRecordFilterGroup); + + if (!alreadyHasAdvancedFilterGroup) { + setHasInitializedCurrentRecordFilters(false); + + const newRecordFilterGroup = { + id: v4(), + logicalOperator: RecordFilterGroupLogicalOperator.AND, + }; + + upsertRecordFilterGroup(newRecordFilterGroup); + + if (!isDefined(defaultFieldMetadataItem)) { + throw new Error('Missing default filter definition'); + } + + const { newRecordFilter } = createEmptyRecordFilterFromFieldMetadataItem( + defaultFieldMetadataItem, + ); + + newRecordFilter.recordFilterGroupId = newRecordFilterGroup.id; + + upsertRecordFilter(newRecordFilter); + } + }; + + return ( +