diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownRecordSelect.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownRecordSelect.tsx index 0323a75d6d..9a61611745 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownRecordSelect.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownRecordSelect.tsx @@ -55,7 +55,11 @@ export const ObjectFilterDropdownRecordSelect = ({ const selectedFilter = useRecoilValue(selectedFilterState); const objectNameSingular = - filterDefinitionUsedInDropdown?.relationObjectMetadataNameSingular ?? ''; + filterDefinitionUsedInDropdown?.relationObjectMetadataNameSingular; + + if (!isDefined(objectNameSingular)) { + throw new Error('objectNameSingular is not defined'); + } const { loading, filteredSelectedRecords, recordsToSelect, selectedRecords } = useRecordsForSelect({ diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useSetFilterDefinitionUsedInDropdownInScope.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useSetFilterDefinitionUsedInDropdownInScope.ts new file mode 100644 index 0000000000..85a515c6d1 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useSetFilterDefinitionUsedInDropdownInScope.ts @@ -0,0 +1,22 @@ +import { useRecoilCallback } from 'recoil'; +import { filterDefinitionUsedInDropdownComponentState } from '../states/filterDefinitionUsedInDropdownComponentState'; +import { FilterDefinition } from '../types/FilterDefinition'; +import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState'; + +export const useSetFilterDefinitionUsedInDropdownInScope = () => { + const setFilterDefinitionUsedInDropdownInScope = useRecoilCallback( + ({ set }) => + (scopeId: string, filterDefinition: FilterDefinition | null) => { + const filterDefinitionUsedInDropdownState = extractComponentState( + filterDefinitionUsedInDropdownComponentState, + scopeId, + ); + set(filterDefinitionUsedInDropdownState, filterDefinition); + }, + [], + ); + + return { + setFilterDefinitionUsedInDropdownInScope, + }; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleColumnFilter.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleColumnFilter.ts index f15fe3ea96..1052a38522 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleColumnFilter.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleColumnFilter.ts @@ -3,12 +3,16 @@ import { v4 } from 'uuid'; import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; -import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions'; +import { useSetFilterDefinitionUsedInDropdownInScope } from '@/object-record/object-filter-dropdown/hooks/useSetFilterDefinitionUsedInDropdownInScope'; import { Filter } from '@/object-record/object-filter-dropdown/types/Filter'; -import { FilterDefinition } from '@/object-record/object-filter-dropdown/types/FilterDefinition'; import { getOperandsForFilterDefinition } from '@/object-record/object-filter-dropdown/utils/getOperandsForFilterType'; -import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2'; +import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; +import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState'; +import { useGetCurrentView } from '@/views/hooks/useGetCurrentView'; import { useUpsertCombinedViewFilters } from '@/views/hooks/useUpsertCombinedViewFilters'; +import { availableFilterDefinitionsComponentState } from '@/views/states/availableFilterDefinitionsComponentState'; +import { useRecoilCallback } from 'recoil'; import { isDefined } from '~/utils/isDefined'; type UseHandleToggleColumnFilterProps = { @@ -17,8 +21,8 @@ type UseHandleToggleColumnFilterProps = { }; export const useHandleToggleColumnFilter = ({ - viewBarId, objectNameSingular, + viewBarId, }: UseHandleToggleColumnFilterProps) => { const { objectMetadataItem } = useObjectMetadataItem({ objectNameSingular, @@ -28,10 +32,29 @@ export const useHandleToggleColumnFilter = ({ useColumnDefinitionsFromFieldMetadata(objectMetadataItem); const { upsertCombinedViewFilter } = useUpsertCombinedViewFilters(viewBarId); - const { openDropdown } = useDropdownV2(); + + const openDropdown = useRecoilCallback(({ set }) => { + return (dropdownId: string) => { + const dropdownOpenState = extractComponentState( + isDropdownOpenComponentState, + dropdownId, + ); + + set(dropdownOpenState, true); + }; + }, []); + + const availableFilterDefinitions = useRecoilComponentValueV2( + availableFilterDefinitionsComponentState, + ); + + const { currentViewWithCombinedFiltersAndSorts } = useGetCurrentView(); + + const { setFilterDefinitionUsedInDropdownInScope } = + useSetFilterDefinitionUsedInDropdownInScope(); const handleToggleColumnFilter = useCallback( - (fieldMetadataId: string) => { + async (fieldMetadataId: string) => { const correspondingColumnDefinition = columnDefinitions.find( (columnDefinition) => columnDefinition.fieldMetadataId === fieldMetadataId, @@ -39,38 +62,54 @@ export const useHandleToggleColumnFilter = ({ if (!isDefined(correspondingColumnDefinition)) return; - const filterType = getFilterTypeFromFieldType( - correspondingColumnDefinition?.type, - ); + const newFilterId = v4(); - const filterDefinition = { - label: correspondingColumnDefinition.label, - iconName: correspondingColumnDefinition.iconName, - fieldMetadataId, - type: filterType, - } satisfies FilterDefinition; + const existingViewFilter = + currentViewWithCombinedFiltersAndSorts?.viewFilters.find( + (viewFilter) => viewFilter.fieldMetadataId === fieldMetadataId, + ); - const availableOperandsForFilter = - getOperandsForFilterDefinition(filterDefinition); + if (!existingViewFilter) { + const filterDefinition = availableFilterDefinitions.find( + (fd) => fd.fieldMetadataId === fieldMetadataId, + ); - const defaultOperand = availableOperandsForFilter[0]; + if (!isDefined(filterDefinition)) { + throw new Error('Filter definition not found'); + } - const newFilter: Filter = { - id: v4(), - fieldMetadataId, - operand: defaultOperand, - displayValue: '', - definition: filterDefinition, - value: '', - }; + const availableOperandsForFilter = + getOperandsForFilterDefinition(filterDefinition); - upsertCombinedViewFilter(newFilter); + const defaultOperand = availableOperandsForFilter[0]; - openDropdown(newFilter.id, { - scope: newFilter.id, - }); + const newFilter: Filter = { + id: newFilterId, + fieldMetadataId, + operand: defaultOperand, + displayValue: '', + definition: filterDefinition, + value: '', + }; + + await upsertCombinedViewFilter(newFilter); + + setFilterDefinitionUsedInDropdownInScope( + newFilter.id, + filterDefinition, + ); + } + + openDropdown(existingViewFilter?.id ?? newFilterId); }, - [columnDefinitions, upsertCombinedViewFilter, openDropdown], + [ + openDropdown, + columnDefinitions, + upsertCombinedViewFilter, + setFilterDefinitionUsedInDropdownInScope, + currentViewWithCombinedFiltersAndSorts, + availableFilterDefinitions, + ], ); return handleToggleColumnFilter; diff --git a/packages/twenty-front/vite.config.ts b/packages/twenty-front/vite.config.ts index eec22a826b..25d84582fd 100644 --- a/packages/twenty-front/vite.config.ts +++ b/packages/twenty-front/vite.config.ts @@ -2,8 +2,8 @@ import { isNonEmptyString } from '@sniptt/guards'; import react from '@vitejs/plugin-react-swc'; import wyw from '@wyw-in-js/vite'; -import path from 'path'; import fs from 'fs'; +import path from 'path'; import { defineConfig, loadEnv, searchForWorkspaceRoot } from 'vite'; import checker from 'vite-plugin-checker'; import svgr from 'vite-plugin-svgr'; @@ -133,7 +133,7 @@ export default defineConfig(({ command, mode }) => { ], optimizeDeps: { - exclude: ['node_modules/.vite', 'node_modules/.cache'], + exclude: ['../../node_modules/.vite', '../../node_modules/.cache'], }, build: {