Refactored table filters to consume new currentRecordFilters component state (#9652)
This PR implements a first real use case, now currentRecordFilters component state acts as the global record filter reference. It is set by the view initially and can be reset to view filters state at any point. This new state is also modified by two new upsertRecordFilter / removeRecordFilter hooks that will be drop-in replacement of the actual upsertCombinedViewFilter and removeCombinediewFilter hooks. This PR implements the logic to manipulate record filters but only reads it to make the table find many request, all other features are still relying on the old view filter implementation. Advanced filters are ignored because they are hidden and because this effort is made precisely to allow the completion of the advanced filters feature.
This commit is contained in:
@ -11,6 +11,7 @@ import { ObjectFilterOperandSelectAndInput } from '@/object-record/object-filter
|
||||
import { filterDefinitionUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/filterDefinitionUsedInDropdownComponentState';
|
||||
import { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState';
|
||||
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
||||
import { useRemoveRecordFilter } from '@/object-record/record-filter/hooks/useRemoveRecordFilter';
|
||||
import { RecordFilterOperand } from '@/object-record/record-filter/types/RecordFilterOperand';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
import { useDeleteCombinedViewFilters } from '@/views/hooks/useDeleteCombinedViewFilters';
|
||||
@ -73,14 +74,17 @@ export const EditableFilterDropdownButton = ({
|
||||
viewFilterDropdownId,
|
||||
]);
|
||||
|
||||
const { removeRecordFilter } = useRemoveRecordFilter();
|
||||
|
||||
const handleRemove = () => {
|
||||
closeDropdown();
|
||||
|
||||
deleteCombinedViewFilter(viewFilter.id);
|
||||
removeRecordFilter(viewFilter.fieldMetadataId);
|
||||
};
|
||||
|
||||
const handleDropdownClickOutside = useCallback(() => {
|
||||
const { id: fieldId, value, operand } = viewFilter;
|
||||
const { id: fieldId, value, operand, fieldMetadataId } = viewFilter;
|
||||
if (
|
||||
!value &&
|
||||
![
|
||||
@ -91,9 +95,10 @@ export const EditableFilterDropdownButton = ({
|
||||
RecordFilterOperand.IsToday,
|
||||
].includes(operand)
|
||||
) {
|
||||
removeRecordFilter(fieldMetadataId);
|
||||
deleteCombinedViewFilter(fieldId);
|
||||
}
|
||||
}, [viewFilter, deleteCombinedViewFilter]);
|
||||
}, [viewFilter, deleteCombinedViewFilter, removeRecordFilter]);
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
|
||||
@ -3,6 +3,7 @@ import { useEffect } from 'react';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useSetRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentFamilyStateV2';
|
||||
import { useViewFromQueryParams } from '@/views/hooks/internal/useViewFromQueryParams';
|
||||
import { useApplyViewFiltersToCurrentRecordFilters } from '@/views/hooks/useApplyViewFiltersToCurrentRecordFilters';
|
||||
import { useResetUnsavedViewStates } from '@/views/hooks/useResetUnsavedViewStates';
|
||||
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
||||
import { unsavedToUpsertViewFiltersComponentFamilyState } from '@/views/states/unsavedToUpsertViewFiltersComponentFamilyState';
|
||||
@ -20,6 +21,9 @@ export const QueryParamsFiltersEffect = () => {
|
||||
|
||||
const { resetUnsavedViewStates } = useResetUnsavedViewStates();
|
||||
|
||||
const { applyViewFiltersToCurrentRecordFilters } =
|
||||
useApplyViewFiltersToCurrentRecordFilters();
|
||||
|
||||
useEffect(() => {
|
||||
if (!hasFiltersQueryParams) {
|
||||
return;
|
||||
@ -27,10 +31,12 @@ export const QueryParamsFiltersEffect = () => {
|
||||
|
||||
getFiltersFromQueryParams().then((filtersFromParams) => {
|
||||
if (Array.isArray(filtersFromParams)) {
|
||||
applyViewFiltersToCurrentRecordFilters(filtersFromParams);
|
||||
setUnsavedViewFilter(filtersFromParams);
|
||||
}
|
||||
});
|
||||
}, [
|
||||
applyViewFiltersToCurrentRecordFilters,
|
||||
getFiltersFromQueryParams,
|
||||
hasFiltersQueryParams,
|
||||
resetUnsavedViewStates,
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { useIcons } from 'twenty-ui';
|
||||
|
||||
import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural';
|
||||
import { useRemoveRecordFilter } from '@/object-record/record-filter/hooks/useRemoveRecordFilter';
|
||||
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { useHandleToggleTrashColumnFilter } from '@/object-record/record-index/hooks/useHandleToggleTrashColumnFilter';
|
||||
import { SortOrFilterChip } from '@/views/components/SortOrFilterChip';
|
||||
@ -29,10 +30,14 @@ export const VariantFilterChip = ({
|
||||
viewBarId,
|
||||
});
|
||||
|
||||
const { removeRecordFilter } = useRemoveRecordFilter();
|
||||
|
||||
const { getIcon } = useIcons();
|
||||
|
||||
const handleRemoveClick = () => {
|
||||
deleteCombinedViewFilter(viewFilter.id);
|
||||
removeRecordFilter(viewFilter.fieldMetadataId);
|
||||
|
||||
if (
|
||||
viewFilter.definition.label === 'Deleted' &&
|
||||
viewFilter.operand === 'isNotEmpty'
|
||||
|
||||
@ -21,6 +21,7 @@ import { ViewsHotkeyScope } from '../types/ViewsHotkeyScope';
|
||||
import { FiltersHotkeyScope } from '@/object-record/object-filter-dropdown/types/FiltersHotkeyScope';
|
||||
import { VIEW_SORT_DROPDOWN_ID } from '@/object-record/object-sort-dropdown/constants/ViewSortDropdownId';
|
||||
import { ObjectSortDropdownComponentInstanceContext } from '@/object-record/object-sort-dropdown/states/context/ObjectSortDropdownComponentInstanceContext';
|
||||
import { ViewBarRecordFilterEffect } from '@/views/components/ViewBarRecordFilterEffect';
|
||||
import { ViewEventContext } from '@/views/events/contexts/ViewEventContext';
|
||||
import { UpdateViewButtonGroup } from './UpdateViewButtonGroup';
|
||||
import { ViewBarDetails } from './ViewBarDetails';
|
||||
@ -53,6 +54,7 @@ export const ViewBar = ({
|
||||
value={{ instanceId: VIEW_SORT_DROPDOWN_ID }}
|
||||
>
|
||||
<ViewEventContext.Provider value={{ onCurrentViewChange }}>
|
||||
<ViewBarRecordFilterEffect />
|
||||
<ViewBarEffect viewBarId={viewBarId} />
|
||||
<ViewBarFilterEffect filterDropdownId={filterDropdownId} />
|
||||
<ViewBarSortEffect />
|
||||
|
||||
@ -14,6 +14,8 @@ import { EditableFilterDropdownButton } from '@/views/components/EditableFilterD
|
||||
import { EditableSortChip } from '@/views/components/EditableSortChip';
|
||||
import { ViewBarFilterEffect } from '@/views/components/ViewBarFilterEffect';
|
||||
import { useViewFromQueryParams } from '@/views/hooks/internal/useViewFromQueryParams';
|
||||
|
||||
import { useApplyCurrentViewFiltersToCurrentRecordFilters } from '@/views/hooks/useApplyCurrentViewFiltersToCurrentRecordFilters';
|
||||
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
||||
import { useResetUnsavedViewStates } from '@/views/hooks/useResetUnsavedViewStates';
|
||||
import { availableFilterDefinitionsComponentState } from '@/views/states/availableFilterDefinitionsComponentState';
|
||||
@ -167,9 +169,13 @@ export const ViewBarDetails = ({
|
||||
};
|
||||
}, [currentViewWithCombinedFiltersAndSorts]);
|
||||
|
||||
const { applyCurrentViewFiltersToCurrentRecordFilters } =
|
||||
useApplyCurrentViewFiltersToCurrentRecordFilters();
|
||||
|
||||
const handleCancelClick = () => {
|
||||
if (isDefined(viewId)) {
|
||||
resetUnsavedViewStates(viewId);
|
||||
applyCurrentViewFiltersToCurrentRecordFilters();
|
||||
toggleSoftDeleteFilterState(false);
|
||||
}
|
||||
};
|
||||
|
||||
@ -1,16 +1,13 @@
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
|
||||
import { filterDefinitionUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/filterDefinitionUsedInDropdownComponentState';
|
||||
import { objectFilterDropdownSelectedOptionValuesComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSelectedOptionValuesComponentState';
|
||||
import { objectFilterDropdownSelectedRecordIdsComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSelectedRecordIdsComponentState';
|
||||
import { onFilterSelectComponentState } from '@/object-record/object-filter-dropdown/states/onFilterSelectComponentState';
|
||||
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
||||
import { useUpsertCombinedViewFilters } from '@/views/hooks/useUpsertCombinedViewFilters';
|
||||
import { availableFilterDefinitionsComponentState } from '@/views/states/availableFilterDefinitionsComponentState';
|
||||
import { jsonRelationFilterValueSchema } from '@/views/view-filter-value/validation-schemas/jsonRelationFilterValueSchema';
|
||||
import { simpleRelationFilterValueSchema } from '@/views/view-filter-value/validation-schemas/simpleRelationFilterValueSchema';
|
||||
@ -23,19 +20,12 @@ type ViewBarFilterEffectProps = {
|
||||
export const ViewBarFilterEffect = ({
|
||||
filterDropdownId,
|
||||
}: ViewBarFilterEffectProps) => {
|
||||
const { upsertCombinedViewFilter } = useUpsertCombinedViewFilters();
|
||||
|
||||
const { currentViewWithCombinedFiltersAndSorts } = useGetCurrentView();
|
||||
|
||||
const availableFilterDefinitions = useRecoilComponentValueV2(
|
||||
availableFilterDefinitionsComponentState,
|
||||
);
|
||||
|
||||
const setOnFilterSelect = useSetRecoilComponentStateV2(
|
||||
onFilterSelectComponentState,
|
||||
filterDropdownId,
|
||||
);
|
||||
|
||||
const filterDefinitionUsedInDropdown = useRecoilComponentValueV2(
|
||||
filterDefinitionUsedInDropdownComponentState,
|
||||
filterDropdownId,
|
||||
@ -62,17 +52,7 @@ export const ViewBarFilterEffect = ({
|
||||
if (isDefined(availableFilterDefinitions)) {
|
||||
setAvailableFilterDefinitions(availableFilterDefinitions);
|
||||
}
|
||||
setOnFilterSelect(() => (filter: RecordFilter | null) => {
|
||||
if (isDefined(filter)) {
|
||||
upsertCombinedViewFilter(filter);
|
||||
}
|
||||
});
|
||||
}, [
|
||||
availableFilterDefinitions,
|
||||
setAvailableFilterDefinitions,
|
||||
setOnFilterSelect,
|
||||
upsertCombinedViewFilter,
|
||||
]);
|
||||
}, [availableFilterDefinitions, setAvailableFilterDefinitions]);
|
||||
|
||||
useEffect(() => {
|
||||
if (filterDefinitionUsedInDropdown?.type === 'RELATION') {
|
||||
|
||||
@ -0,0 +1,50 @@
|
||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
import { availableFilterDefinitionsComponentState } from '@/views/states/availableFilterDefinitionsComponentState';
|
||||
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
||||
import { View } from '@/views/types/View';
|
||||
import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters';
|
||||
import { useEffect } from 'react';
|
||||
import { isDefined } from 'twenty-ui';
|
||||
|
||||
export const ViewBarRecordFilterEffect = () => {
|
||||
const { records: views, isDataPrefetched } = usePrefetchedData<View>(
|
||||
PrefetchKey.AllViews,
|
||||
);
|
||||
|
||||
const currentViewId = useRecoilComponentValueV2(currentViewIdComponentState);
|
||||
|
||||
const setCurrentRecordFilters = useSetRecoilComponentStateV2(
|
||||
currentRecordFiltersComponentState,
|
||||
);
|
||||
|
||||
const availableFilterDefinitions = useRecoilComponentValueV2(
|
||||
availableFilterDefinitionsComponentState,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (isDataPrefetched) {
|
||||
const currentView = views.find((view) => view.id === currentViewId);
|
||||
|
||||
if (isDefined(currentView)) {
|
||||
setCurrentRecordFilters(
|
||||
mapViewFiltersToFilters(
|
||||
currentView.viewFilters,
|
||||
availableFilterDefinitions,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}, [
|
||||
isDataPrefetched,
|
||||
views,
|
||||
availableFilterDefinitions,
|
||||
currentViewId,
|
||||
setCurrentRecordFilters,
|
||||
]);
|
||||
|
||||
return null;
|
||||
};
|
||||
@ -0,0 +1,198 @@
|
||||
import { act, renderHook } from '@testing-library/react';
|
||||
|
||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||
import { RecordFilterDefinition } from '@/object-record/record-filter/types/RecordFilterDefinition';
|
||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { availableFilterDefinitionsComponentState } from '@/views/states/availableFilterDefinitionsComponentState';
|
||||
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
||||
import { ViewFilter } from '@/views/types/ViewFilter';
|
||||
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
||||
import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
|
||||
import { useApplyCurrentViewFiltersToCurrentRecordFilters } from '../useApplyCurrentViewFiltersToCurrentRecordFilters';
|
||||
|
||||
jest.mock('@/prefetch/hooks/usePrefetchedData');
|
||||
|
||||
describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => {
|
||||
const mockFilterDefinition: RecordFilterDefinition = {
|
||||
fieldMetadataId: 'field-1',
|
||||
label: 'Test Field',
|
||||
type: 'TEXT',
|
||||
iconName: 'IconText',
|
||||
};
|
||||
|
||||
const mockViewFilter: ViewFilter = {
|
||||
__typename: 'ViewFilter',
|
||||
id: 'filter-1',
|
||||
fieldMetadataId: 'field-1',
|
||||
operand: ViewFilterOperand.Contains,
|
||||
value: 'test',
|
||||
displayValue: 'test',
|
||||
viewFilterGroupId: 'group-1',
|
||||
positionInViewFilterGroup: 0,
|
||||
definition: mockFilterDefinition,
|
||||
};
|
||||
|
||||
const mockView = {
|
||||
id: 'view-1',
|
||||
name: 'Test View',
|
||||
objectMetadataId: 'object-1',
|
||||
viewFilters: [mockViewFilter],
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
(usePrefetchedData as jest.Mock).mockReturnValue({
|
||||
records: [mockView],
|
||||
});
|
||||
});
|
||||
|
||||
it('should apply filters from current view', () => {
|
||||
const { result } = renderHook(
|
||||
() => {
|
||||
const { applyCurrentViewFiltersToCurrentRecordFilters } =
|
||||
useApplyCurrentViewFiltersToCurrentRecordFilters();
|
||||
|
||||
const currentFilters = useRecoilComponentValueV2(
|
||||
currentRecordFiltersComponentState,
|
||||
);
|
||||
|
||||
return {
|
||||
applyCurrentViewFiltersToCurrentRecordFilters,
|
||||
currentFilters,
|
||||
};
|
||||
},
|
||||
{
|
||||
wrapper: getJestMetadataAndApolloMocksWrapper({
|
||||
onInitializeRecoilSnapshot: (snapshot) => {
|
||||
snapshot.set(
|
||||
currentViewIdComponentState.atomFamily({
|
||||
instanceId: 'instanceId',
|
||||
}),
|
||||
mockView.id,
|
||||
);
|
||||
snapshot.set(
|
||||
availableFilterDefinitionsComponentState.atomFamily({
|
||||
instanceId: 'instanceId',
|
||||
}),
|
||||
[mockFilterDefinition],
|
||||
);
|
||||
},
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
act(() => {
|
||||
result.current.applyCurrentViewFiltersToCurrentRecordFilters();
|
||||
});
|
||||
|
||||
expect(result.current.currentFilters).toEqual([
|
||||
{
|
||||
id: mockViewFilter.id,
|
||||
fieldMetadataId: mockViewFilter.fieldMetadataId,
|
||||
value: mockViewFilter.value,
|
||||
displayValue: mockViewFilter.displayValue,
|
||||
operand: mockViewFilter.operand,
|
||||
viewFilterGroupId: mockViewFilter.viewFilterGroupId,
|
||||
positionInViewFilterGroup: mockViewFilter.positionInViewFilterGroup,
|
||||
definition: mockFilterDefinition,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should not apply filters when current view is not found', () => {
|
||||
(usePrefetchedData as jest.Mock).mockReturnValue({
|
||||
records: [],
|
||||
});
|
||||
|
||||
const { result } = renderHook(
|
||||
() => {
|
||||
const { applyCurrentViewFiltersToCurrentRecordFilters } =
|
||||
useApplyCurrentViewFiltersToCurrentRecordFilters();
|
||||
|
||||
const currentFilters = useRecoilComponentValueV2(
|
||||
currentRecordFiltersComponentState,
|
||||
);
|
||||
|
||||
return {
|
||||
applyCurrentViewFiltersToCurrentRecordFilters,
|
||||
currentFilters,
|
||||
};
|
||||
},
|
||||
{
|
||||
wrapper: getJestMetadataAndApolloMocksWrapper({
|
||||
onInitializeRecoilSnapshot: (snapshot) => {
|
||||
snapshot.set(
|
||||
currentViewIdComponentState.atomFamily({
|
||||
instanceId: 'instanceId',
|
||||
}),
|
||||
mockView.id,
|
||||
);
|
||||
snapshot.set(
|
||||
availableFilterDefinitionsComponentState.atomFamily({
|
||||
instanceId: 'instanceId',
|
||||
}),
|
||||
[mockFilterDefinition],
|
||||
);
|
||||
},
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
act(() => {
|
||||
result.current.applyCurrentViewFiltersToCurrentRecordFilters();
|
||||
});
|
||||
|
||||
expect(result.current.currentFilters).toEqual([]);
|
||||
});
|
||||
|
||||
it('should handle view with empty filters', () => {
|
||||
const viewWithNoFilters = {
|
||||
...mockView,
|
||||
viewFilters: [],
|
||||
};
|
||||
|
||||
(usePrefetchedData as jest.Mock).mockReturnValue({
|
||||
records: [viewWithNoFilters],
|
||||
});
|
||||
|
||||
const { result } = renderHook(
|
||||
() => {
|
||||
const { applyCurrentViewFiltersToCurrentRecordFilters } =
|
||||
useApplyCurrentViewFiltersToCurrentRecordFilters();
|
||||
|
||||
const currentFilters = useRecoilComponentValueV2(
|
||||
currentRecordFiltersComponentState,
|
||||
);
|
||||
|
||||
return {
|
||||
applyCurrentViewFiltersToCurrentRecordFilters,
|
||||
currentFilters,
|
||||
};
|
||||
},
|
||||
{
|
||||
wrapper: getJestMetadataAndApolloMocksWrapper({
|
||||
onInitializeRecoilSnapshot: (snapshot) => {
|
||||
snapshot.set(
|
||||
currentViewIdComponentState.atomFamily({
|
||||
instanceId: 'instanceId',
|
||||
}),
|
||||
mockView.id,
|
||||
);
|
||||
snapshot.set(
|
||||
availableFilterDefinitionsComponentState.atomFamily({
|
||||
instanceId: 'instanceId',
|
||||
}),
|
||||
[mockFilterDefinition],
|
||||
);
|
||||
},
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
act(() => {
|
||||
result.current.applyCurrentViewFiltersToCurrentRecordFilters();
|
||||
});
|
||||
|
||||
expect(result.current.currentFilters).toEqual([]);
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,108 @@
|
||||
import { act, renderHook } from '@testing-library/react';
|
||||
|
||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||
import { RecordFilterDefinition } from '@/object-record/record-filter/types/RecordFilterDefinition';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { availableFilterDefinitionsComponentState } from '@/views/states/availableFilterDefinitionsComponentState';
|
||||
import { ViewFilter } from '@/views/types/ViewFilter';
|
||||
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
||||
import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
|
||||
import { useApplyViewFiltersToCurrentRecordFilters } from '../useApplyViewFiltersToCurrentRecordFilters';
|
||||
|
||||
describe('useApplyViewFiltersToCurrentRecordFilters', () => {
|
||||
const mockAvailableFilterDefinition: RecordFilterDefinition = {
|
||||
fieldMetadataId: 'field-1',
|
||||
label: 'Test Field',
|
||||
type: 'TEXT',
|
||||
iconName: 'IconText',
|
||||
};
|
||||
|
||||
const mockViewFilter: ViewFilter = {
|
||||
__typename: 'ViewFilter',
|
||||
id: 'filter-1',
|
||||
fieldMetadataId: 'field-1',
|
||||
operand: ViewFilterOperand.Contains,
|
||||
value: 'test',
|
||||
displayValue: 'test',
|
||||
viewFilterGroupId: 'group-1',
|
||||
positionInViewFilterGroup: 0,
|
||||
definition: mockAvailableFilterDefinition,
|
||||
};
|
||||
|
||||
it('should apply view filters to current record filters', () => {
|
||||
const { result } = renderHook(
|
||||
() => {
|
||||
const { applyViewFiltersToCurrentRecordFilters } =
|
||||
useApplyViewFiltersToCurrentRecordFilters();
|
||||
|
||||
const currentFilters = useRecoilComponentValueV2(
|
||||
currentRecordFiltersComponentState,
|
||||
);
|
||||
|
||||
return { applyViewFiltersToCurrentRecordFilters, currentFilters };
|
||||
},
|
||||
{
|
||||
wrapper: getJestMetadataAndApolloMocksWrapper({
|
||||
onInitializeRecoilSnapshot: (snapshot) => {
|
||||
snapshot.set(
|
||||
availableFilterDefinitionsComponentState.atomFamily({
|
||||
instanceId: 'instanceId',
|
||||
}),
|
||||
[mockAvailableFilterDefinition],
|
||||
);
|
||||
},
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
act(() => {
|
||||
result.current.applyViewFiltersToCurrentRecordFilters([mockViewFilter]);
|
||||
});
|
||||
|
||||
expect(result.current.currentFilters).toEqual([
|
||||
{
|
||||
id: mockViewFilter.id,
|
||||
fieldMetadataId: mockViewFilter.fieldMetadataId,
|
||||
value: mockViewFilter.value,
|
||||
displayValue: mockViewFilter.displayValue,
|
||||
operand: mockViewFilter.operand,
|
||||
viewFilterGroupId: mockViewFilter.viewFilterGroupId,
|
||||
positionInViewFilterGroup: mockViewFilter.positionInViewFilterGroup,
|
||||
definition: mockAvailableFilterDefinition,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should handle empty view filters array', () => {
|
||||
const { result } = renderHook(
|
||||
() => {
|
||||
const { applyViewFiltersToCurrentRecordFilters } =
|
||||
useApplyViewFiltersToCurrentRecordFilters();
|
||||
|
||||
const currentFilters = useRecoilComponentValueV2(
|
||||
currentRecordFiltersComponentState,
|
||||
);
|
||||
|
||||
return { applyViewFiltersToCurrentRecordFilters, currentFilters };
|
||||
},
|
||||
{
|
||||
wrapper: getJestMetadataAndApolloMocksWrapper({
|
||||
onInitializeRecoilSnapshot: (snapshot) => {
|
||||
snapshot.set(
|
||||
availableFilterDefinitionsComponentState.atomFamily({
|
||||
instanceId: 'instanceId',
|
||||
}),
|
||||
[mockAvailableFilterDefinition],
|
||||
);
|
||||
},
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
act(() => {
|
||||
result.current.applyViewFiltersToCurrentRecordFilters([]);
|
||||
});
|
||||
|
||||
expect(result.current.currentFilters).toEqual([]);
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,42 @@
|
||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
import { availableFilterDefinitionsComponentState } from '@/views/states/availableFilterDefinitionsComponentState';
|
||||
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
||||
import { View } from '@/views/types/View';
|
||||
import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters';
|
||||
|
||||
import { isDefined } from 'twenty-ui';
|
||||
|
||||
export const useApplyCurrentViewFiltersToCurrentRecordFilters = () => {
|
||||
const { records: views } = usePrefetchedData<View>(PrefetchKey.AllViews);
|
||||
|
||||
const currentViewId = useRecoilComponentValueV2(currentViewIdComponentState);
|
||||
|
||||
const setCurrentRecordFilters = useSetRecoilComponentStateV2(
|
||||
currentRecordFiltersComponentState,
|
||||
);
|
||||
|
||||
const availableFilterDefinitions = useRecoilComponentValueV2(
|
||||
availableFilterDefinitionsComponentState,
|
||||
);
|
||||
|
||||
const applyCurrentViewFiltersToCurrentRecordFilters = () => {
|
||||
const currentView = views.find((view) => view.id === currentViewId);
|
||||
|
||||
if (isDefined(currentView)) {
|
||||
setCurrentRecordFilters(
|
||||
mapViewFiltersToFilters(
|
||||
currentView.viewFilters,
|
||||
availableFilterDefinitions,
|
||||
),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
applyCurrentViewFiltersToCurrentRecordFilters,
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,31 @@
|
||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
import { availableFilterDefinitionsComponentState } from '@/views/states/availableFilterDefinitionsComponentState';
|
||||
import { ViewFilter } from '@/views/types/ViewFilter';
|
||||
import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters';
|
||||
|
||||
export const useApplyViewFiltersToCurrentRecordFilters = () => {
|
||||
const setCurrentRecordFilters = useSetRecoilComponentStateV2(
|
||||
currentRecordFiltersComponentState,
|
||||
);
|
||||
|
||||
const availableFilterDefinitions = useRecoilComponentValueV2(
|
||||
availableFilterDefinitionsComponentState,
|
||||
);
|
||||
|
||||
const applyViewFiltersToCurrentRecordFilters = (
|
||||
viewFilters: ViewFilter[],
|
||||
) => {
|
||||
const recordFiltersToApply = mapViewFiltersToFilters(
|
||||
viewFilters,
|
||||
availableFilterDefinitions,
|
||||
);
|
||||
|
||||
setCurrentRecordFilters(recordFiltersToApply);
|
||||
};
|
||||
|
||||
return {
|
||||
applyViewFiltersToCurrentRecordFilters,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user