Fix: open filter from column (#8747)

Column filter button (image below) was broken for all filter types, this
PR fixes it.

<img width="1053" alt="broken-filter-button"
src="https://github.com/user-attachments/assets/febd10a8-f360-4245-ba06-ef847c79fde1">

---------

Co-authored-by: Félix Malfait <felix@twenty.com>
This commit is contained in:
ad-elias 2024-11-26 10:52:45 +01:00 committed by GitHub
parent 64b8fd544c
commit eea2885cbd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 99 additions and 34 deletions

View File

@ -55,7 +55,11 @@ export const ObjectFilterDropdownRecordSelect = ({
const selectedFilter = useRecoilValue(selectedFilterState); const selectedFilter = useRecoilValue(selectedFilterState);
const objectNameSingular = const objectNameSingular =
filterDefinitionUsedInDropdown?.relationObjectMetadataNameSingular ?? ''; filterDefinitionUsedInDropdown?.relationObjectMetadataNameSingular;
if (!isDefined(objectNameSingular)) {
throw new Error('objectNameSingular is not defined');
}
const { loading, filteredSelectedRecords, recordsToSelect, selectedRecords } = const { loading, filteredSelectedRecords, recordsToSelect, selectedRecords } =
useRecordsForSelect({ useRecordsForSelect({

View File

@ -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,
};
};

View File

@ -3,12 +3,16 @@ import { v4 } from 'uuid';
import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata'; import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; 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 { 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 { 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 { useUpsertCombinedViewFilters } from '@/views/hooks/useUpsertCombinedViewFilters';
import { availableFilterDefinitionsComponentState } from '@/views/states/availableFilterDefinitionsComponentState';
import { useRecoilCallback } from 'recoil';
import { isDefined } from '~/utils/isDefined'; import { isDefined } from '~/utils/isDefined';
type UseHandleToggleColumnFilterProps = { type UseHandleToggleColumnFilterProps = {
@ -17,8 +21,8 @@ type UseHandleToggleColumnFilterProps = {
}; };
export const useHandleToggleColumnFilter = ({ export const useHandleToggleColumnFilter = ({
viewBarId,
objectNameSingular, objectNameSingular,
viewBarId,
}: UseHandleToggleColumnFilterProps) => { }: UseHandleToggleColumnFilterProps) => {
const { objectMetadataItem } = useObjectMetadataItem({ const { objectMetadataItem } = useObjectMetadataItem({
objectNameSingular, objectNameSingular,
@ -28,10 +32,29 @@ export const useHandleToggleColumnFilter = ({
useColumnDefinitionsFromFieldMetadata(objectMetadataItem); useColumnDefinitionsFromFieldMetadata(objectMetadataItem);
const { upsertCombinedViewFilter } = useUpsertCombinedViewFilters(viewBarId); 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( const handleToggleColumnFilter = useCallback(
(fieldMetadataId: string) => { async (fieldMetadataId: string) => {
const correspondingColumnDefinition = columnDefinitions.find( const correspondingColumnDefinition = columnDefinitions.find(
(columnDefinition) => (columnDefinition) =>
columnDefinition.fieldMetadataId === fieldMetadataId, columnDefinition.fieldMetadataId === fieldMetadataId,
@ -39,38 +62,54 @@ export const useHandleToggleColumnFilter = ({
if (!isDefined(correspondingColumnDefinition)) return; if (!isDefined(correspondingColumnDefinition)) return;
const filterType = getFilterTypeFromFieldType( const newFilterId = v4();
correspondingColumnDefinition?.type,
);
const filterDefinition = { const existingViewFilter =
label: correspondingColumnDefinition.label, currentViewWithCombinedFiltersAndSorts?.viewFilters.find(
iconName: correspondingColumnDefinition.iconName, (viewFilter) => viewFilter.fieldMetadataId === fieldMetadataId,
fieldMetadataId, );
type: filterType,
} satisfies FilterDefinition;
const availableOperandsForFilter = if (!existingViewFilter) {
getOperandsForFilterDefinition(filterDefinition); 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 = { const availableOperandsForFilter =
id: v4(), getOperandsForFilterDefinition(filterDefinition);
fieldMetadataId,
operand: defaultOperand,
displayValue: '',
definition: filterDefinition,
value: '',
};
upsertCombinedViewFilter(newFilter); const defaultOperand = availableOperandsForFilter[0];
openDropdown(newFilter.id, { const newFilter: Filter = {
scope: newFilter.id, 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; return handleToggleColumnFilter;

View File

@ -2,8 +2,8 @@
import { isNonEmptyString } from '@sniptt/guards'; import { isNonEmptyString } from '@sniptt/guards';
import react from '@vitejs/plugin-react-swc'; import react from '@vitejs/plugin-react-swc';
import wyw from '@wyw-in-js/vite'; import wyw from '@wyw-in-js/vite';
import path from 'path';
import fs from 'fs'; import fs from 'fs';
import path from 'path';
import { defineConfig, loadEnv, searchForWorkspaceRoot } from 'vite'; import { defineConfig, loadEnv, searchForWorkspaceRoot } from 'vite';
import checker from 'vite-plugin-checker'; import checker from 'vite-plugin-checker';
import svgr from 'vite-plugin-svgr'; import svgr from 'vite-plugin-svgr';
@ -133,7 +133,7 @@ export default defineConfig(({ command, mode }) => {
], ],
optimizeDeps: { optimizeDeps: {
exclude: ['node_modules/.vite', 'node_modules/.cache'], exclude: ['../../node_modules/.vite', '../../node_modules/.cache'],
}, },
build: { build: {