Refactor duplication of hard coded soft delete filter logic (#10058)
This PR adds a useCheckIsSoftDeleteFilter hook instead of the undocumented in-place logic to retrieve the soft delete filter. Also took the opportunity to refactor a recent change of @prastoin with it. Split VariantFilterChip into SoftDeleteFilterChip and RecordFilterChip to separate concerns about this soft delete filtering.
This commit is contained in:
@ -8,8 +8,8 @@ import { BACKEND_BATCH_REQUEST_MAX_COUNT } from '@/object-record/constants/Backe
|
|||||||
import { DEFAULT_QUERY_PAGE_SIZE } from '@/object-record/constants/DefaultQueryPageSize';
|
import { DEFAULT_QUERY_PAGE_SIZE } from '@/object-record/constants/DefaultQueryPageSize';
|
||||||
import { useDeleteManyRecords } from '@/object-record/hooks/useDeleteManyRecords';
|
import { useDeleteManyRecords } from '@/object-record/hooks/useDeleteManyRecords';
|
||||||
import { useLazyFetchAllRecords } from '@/object-record/hooks/useLazyFetchAllRecords';
|
import { useLazyFetchAllRecords } from '@/object-record/hooks/useLazyFetchAllRecords';
|
||||||
|
import { useCheckIsSoftDeleteFilter } from '@/object-record/record-filter/hooks/useCheckIsSoftDeleteFilter';
|
||||||
import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
|
import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
|
||||||
import { RecordFilterOperand } from '@/object-record/record-filter/types/RecordFilterOperand';
|
|
||||||
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
||||||
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
|
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
@ -50,14 +50,10 @@ export const useDeleteMultipleRecordsAction: ActionHookWithObjectMetadataItem =
|
|||||||
filterValueDependencies,
|
filterValueDependencies,
|
||||||
);
|
);
|
||||||
|
|
||||||
const deletedAtFieldMetadata = objectMetadataItem.fields.find(
|
const { checkIsSoftDeleteFilter } = useCheckIsSoftDeleteFilter();
|
||||||
(field) => field.name === 'deletedAt',
|
|
||||||
);
|
|
||||||
|
|
||||||
const isDeletedFilterActive = contextStoreFilters.some(
|
const isDeletedFilterActive = contextStoreFilters.some(
|
||||||
(filter) =>
|
checkIsSoftDeleteFilter,
|
||||||
filter.fieldMetadataId === deletedAtFieldMetadata?.id &&
|
|
||||||
filter.operand === RecordFilterOperand.IsNotEmpty,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const { fetchAllRecords: fetchAllRecordIds } = useLazyFetchAllRecords({
|
const { fetchAllRecords: fetchAllRecordIds } = useLazyFetchAllRecords({
|
||||||
|
|||||||
@ -45,7 +45,6 @@ describe('computeContextStoreFilters', () => {
|
|||||||
const contextStoreFilters: RecordFilter[] = [
|
const contextStoreFilters: RecordFilter[] = [
|
||||||
{
|
{
|
||||||
id: 'name-filter',
|
id: 'name-filter',
|
||||||
variant: 'default',
|
|
||||||
fieldMetadataId: personObjectMetadataItem.fields.find(
|
fieldMetadataId: personObjectMetadataItem.fields.find(
|
||||||
(field) => field.name === 'name',
|
(field) => field.name === 'name',
|
||||||
)!.id,
|
)!.id,
|
||||||
|
|||||||
@ -0,0 +1,35 @@
|
|||||||
|
import { useFilterableFieldMetadataItems } from '@/object-record/record-filter/hooks/useFilterableFieldMetadataItems';
|
||||||
|
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||||
|
import { RecordFilterOperand } from '@/object-record/record-filter/types/RecordFilterOperand';
|
||||||
|
import { isSoftDeleteFilterActiveComponentState } from '@/object-record/record-table/states/isSoftDeleteFilterActiveComponentState';
|
||||||
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
|
import { isDefined } from 'twenty-shared';
|
||||||
|
|
||||||
|
export const useCheckIsSoftDeleteFilter = () => {
|
||||||
|
const { filterableFieldMetadataItems } = useFilterableFieldMetadataItems();
|
||||||
|
|
||||||
|
const isSoftDeleteFilterActive = useRecoilComponentValueV2(
|
||||||
|
isSoftDeleteFilterActiveComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const checkIsSoftDeleteFilter = (recordFilter: RecordFilter) => {
|
||||||
|
const foundFieldMetadataItem = filterableFieldMetadataItems.find(
|
||||||
|
(fieldMetadataItem) =>
|
||||||
|
fieldMetadataItem.id === recordFilter.fieldMetadataId,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!isDefined(foundFieldMetadataItem)) {
|
||||||
|
throw new Error(
|
||||||
|
`Field metadata item not found for field metadata id: ${recordFilter.fieldMetadataId}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
foundFieldMetadataItem.name === 'deletedAt' &&
|
||||||
|
isSoftDeleteFilterActive &&
|
||||||
|
recordFilter.operand === RecordFilterOperand.IsNotEmpty
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return { checkIsSoftDeleteFilter };
|
||||||
|
};
|
||||||
@ -4,7 +4,6 @@ import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
|||||||
|
|
||||||
export type RecordFilter = {
|
export type RecordFilter = {
|
||||||
id: string;
|
id: string;
|
||||||
variant?: 'default' | 'danger';
|
|
||||||
fieldMetadataId: string;
|
fieldMetadataId: string;
|
||||||
value: string;
|
value: string;
|
||||||
displayValue: string;
|
displayValue: string;
|
||||||
|
|||||||
@ -59,10 +59,11 @@ export const useHandleToggleTrashColumnFilter = ({
|
|||||||
|
|
||||||
const newFilter: RecordFilter = {
|
const newFilter: RecordFilter = {
|
||||||
id: v4(),
|
id: v4(),
|
||||||
variant: 'danger',
|
|
||||||
fieldMetadataId: trashFieldMetadata.id,
|
fieldMetadataId: trashFieldMetadata.id,
|
||||||
operand: ViewFilterOperand.IsNotEmpty,
|
operand: ViewFilterOperand.IsNotEmpty,
|
||||||
displayValue: '',
|
displayValue: '',
|
||||||
|
type: filterType,
|
||||||
|
label: `Deleted`,
|
||||||
definition: {
|
definition: {
|
||||||
label: `Deleted`,
|
label: `Deleted`,
|
||||||
iconName: 'IconTrash',
|
iconName: 'IconTrash',
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { IconFilterOff } from 'twenty-ui';
|
import { IconFilterOff } from 'twenty-ui';
|
||||||
|
|
||||||
import { useObjectLabel } from '@/object-metadata/hooks/useObjectLabel';
|
import { useObjectLabel } from '@/object-metadata/hooks/useObjectLabel';
|
||||||
|
import { useCheckIsSoftDeleteFilter } from '@/object-record/record-filter/hooks/useCheckIsSoftDeleteFilter';
|
||||||
import { useRemoveRecordFilter } from '@/object-record/record-filter/hooks/useRemoveRecordFilter';
|
import { useRemoveRecordFilter } from '@/object-record/record-filter/hooks/useRemoveRecordFilter';
|
||||||
import { useHandleToggleTrashColumnFilter } from '@/object-record/record-index/hooks/useHandleToggleTrashColumnFilter';
|
import { useHandleToggleTrashColumnFilter } from '@/object-record/record-index/hooks/useHandleToggleTrashColumnFilter';
|
||||||
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||||
@ -8,6 +9,7 @@ import { RecordTableEmptyStateDisplay } from '@/object-record/record-table/empty
|
|||||||
import { tableFiltersComponentState } from '@/object-record/record-table/states/tableFiltersComponentState';
|
import { tableFiltersComponentState } from '@/object-record/record-table/states/tableFiltersComponentState';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { useDeleteCombinedViewFilters } from '@/views/hooks/useDeleteCombinedViewFilters';
|
import { useDeleteCombinedViewFilters } from '@/views/hooks/useDeleteCombinedViewFilters';
|
||||||
|
import { isDefined } from 'twenty-shared';
|
||||||
|
|
||||||
export const RecordTableEmptyStateSoftDelete = () => {
|
export const RecordTableEmptyStateSoftDelete = () => {
|
||||||
const { objectMetadataItem, objectNameSingular, recordTableId } =
|
const { objectMetadataItem, objectNameSingular, recordTableId } =
|
||||||
@ -28,12 +30,12 @@ export const RecordTableEmptyStateSoftDelete = () => {
|
|||||||
|
|
||||||
const { removeRecordFilter } = useRemoveRecordFilter();
|
const { removeRecordFilter } = useRemoveRecordFilter();
|
||||||
|
|
||||||
const handleButtonClick = async () => {
|
const { checkIsSoftDeleteFilter } = useCheckIsSoftDeleteFilter();
|
||||||
const deletedFilter = tableFilters.find(
|
|
||||||
(filter) => filter.label === 'Deleted' && filter.operand === 'isNotEmpty',
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!deletedFilter) {
|
const handleButtonClick = async () => {
|
||||||
|
const deletedFilter = tableFilters.find(checkIsSoftDeleteFilter);
|
||||||
|
|
||||||
|
if (!isDefined(deletedFilter)) {
|
||||||
throw new Error('Deleted filter not found');
|
throw new Error('Deleted filter not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
|
import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext';
|
||||||
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
|
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
|
||||||
|
|
||||||
export const isSoftDeleteFilterActiveComponentState =
|
export const isSoftDeleteFilterActiveComponentState =
|
||||||
createComponentStateV2<boolean>({
|
createComponentStateV2<boolean>({
|
||||||
key: 'isSoftDeleteFilterActiveComponentState',
|
key: 'isSoftDeleteFilterActiveComponentState',
|
||||||
defaultValue: false,
|
defaultValue: false,
|
||||||
componentInstanceContext: RecordTableComponentInstanceContext,
|
componentInstanceContext: RecordFiltersComponentInstanceContext,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,36 +1,18 @@
|
|||||||
import { useIcons } from 'twenty-ui';
|
import { useIcons } from 'twenty-ui';
|
||||||
|
|
||||||
import { useFieldMetadataItemById } from '@/object-metadata/hooks/useFieldMetadataItemById';
|
import { useFieldMetadataItemById } from '@/object-metadata/hooks/useFieldMetadataItemById';
|
||||||
import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural';
|
|
||||||
import { useRemoveRecordFilter } from '@/object-record/record-filter/hooks/useRemoveRecordFilter';
|
import { useRemoveRecordFilter } from '@/object-record/record-filter/hooks/useRemoveRecordFilter';
|
||||||
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||||
import { useHandleToggleTrashColumnFilter } from '@/object-record/record-index/hooks/useHandleToggleTrashColumnFilter';
|
|
||||||
import { SortOrFilterChip } from '@/views/components/SortOrFilterChip';
|
import { SortOrFilterChip } from '@/views/components/SortOrFilterChip';
|
||||||
import { useDeleteCombinedViewFilters } from '@/views/hooks/useDeleteCombinedViewFilters';
|
import { useDeleteCombinedViewFilters } from '@/views/hooks/useDeleteCombinedViewFilters';
|
||||||
import { useParams } from 'react-router-dom';
|
|
||||||
|
|
||||||
type VariantFilterChipProps = {
|
type RecordFilterChipProps = {
|
||||||
recordFilter: RecordFilter;
|
recordFilter: RecordFilter;
|
||||||
viewBarId: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const VariantFilterChip = ({
|
export const RecordFilterChip = ({ recordFilter }: RecordFilterChipProps) => {
|
||||||
recordFilter,
|
|
||||||
viewBarId,
|
|
||||||
}: VariantFilterChipProps) => {
|
|
||||||
const { deleteCombinedViewFilter } = useDeleteCombinedViewFilters();
|
const { deleteCombinedViewFilter } = useDeleteCombinedViewFilters();
|
||||||
|
|
||||||
const { objectNamePlural } = useParams();
|
|
||||||
|
|
||||||
const { objectNameSingular } = useObjectNameSingularFromPlural({
|
|
||||||
objectNamePlural: objectNamePlural ?? '',
|
|
||||||
});
|
|
||||||
|
|
||||||
const { toggleSoftDeleteFilterState } = useHandleToggleTrashColumnFilter({
|
|
||||||
objectNameSingular,
|
|
||||||
viewBarId,
|
|
||||||
});
|
|
||||||
|
|
||||||
const { fieldMetadataItem } = useFieldMetadataItemById(
|
const { fieldMetadataItem } = useFieldMetadataItemById(
|
||||||
recordFilter.fieldMetadataId,
|
recordFilter.fieldMetadataId,
|
||||||
);
|
);
|
||||||
@ -44,20 +26,11 @@ export const VariantFilterChip = ({
|
|||||||
const handleRemoveClick = () => {
|
const handleRemoveClick = () => {
|
||||||
deleteCombinedViewFilter(recordFilter.id);
|
deleteCombinedViewFilter(recordFilter.id);
|
||||||
removeRecordFilter(recordFilter.fieldMetadataId);
|
removeRecordFilter(recordFilter.fieldMetadataId);
|
||||||
|
|
||||||
if (
|
|
||||||
recordFilter.label === 'Deleted' &&
|
|
||||||
recordFilter.operand === 'isNotEmpty'
|
|
||||||
) {
|
|
||||||
toggleSoftDeleteFilterState(false);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SortOrFilterChip
|
<SortOrFilterChip
|
||||||
key={recordFilter.fieldMetadataId}
|
|
||||||
testId={recordFilter.fieldMetadataId}
|
testId={recordFilter.fieldMetadataId}
|
||||||
variant={recordFilter.variant}
|
|
||||||
labelValue={recordFilter.label ?? ''}
|
labelValue={recordFilter.label ?? ''}
|
||||||
Icon={FieldMetadataItemIcon}
|
Icon={FieldMetadataItemIcon}
|
||||||
onRemove={handleRemoveClick}
|
onRemove={handleRemoveClick}
|
||||||
@ -0,0 +1,48 @@
|
|||||||
|
import { useIcons } from 'twenty-ui';
|
||||||
|
|
||||||
|
import { useRemoveRecordFilter } from '@/object-record/record-filter/hooks/useRemoveRecordFilter';
|
||||||
|
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||||
|
import { isSoftDeleteFilterActiveComponentState } from '@/object-record/record-table/states/isSoftDeleteFilterActiveComponentState';
|
||||||
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
|
import { SortOrFilterChip } from '@/views/components/SortOrFilterChip';
|
||||||
|
import { useDeleteCombinedViewFilters } from '@/views/hooks/useDeleteCombinedViewFilters';
|
||||||
|
|
||||||
|
type SoftDeleteFilterChipProps = {
|
||||||
|
recordFilter: RecordFilter;
|
||||||
|
viewBarId: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const SoftDeleteFilterChip = ({
|
||||||
|
recordFilter,
|
||||||
|
viewBarId,
|
||||||
|
}: SoftDeleteFilterChipProps) => {
|
||||||
|
const { deleteCombinedViewFilter } = useDeleteCombinedViewFilters();
|
||||||
|
|
||||||
|
const setIsSoftDeleteFilterActive = useSetRecoilComponentStateV2(
|
||||||
|
isSoftDeleteFilterActiveComponentState,
|
||||||
|
viewBarId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const { removeRecordFilter } = useRemoveRecordFilter();
|
||||||
|
|
||||||
|
const { getIcon } = useIcons();
|
||||||
|
|
||||||
|
const handleRemoveClick = () => {
|
||||||
|
deleteCombinedViewFilter(recordFilter.id);
|
||||||
|
removeRecordFilter(recordFilter.fieldMetadataId);
|
||||||
|
|
||||||
|
setIsSoftDeleteFilterActive(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const ChipIcon = getIcon('IconTrash');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SortOrFilterChip
|
||||||
|
testId={recordFilter.fieldMetadataId}
|
||||||
|
variant={'danger'}
|
||||||
|
labelValue={recordFilter.label ?? ''}
|
||||||
|
Icon={ChipIcon}
|
||||||
|
onRemove={handleRemoveClick}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -2,7 +2,7 @@ import { useTheme } from '@emotion/react';
|
|||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { IconComponent, IconX } from 'twenty-ui';
|
import { IconComponent, IconX } from 'twenty-ui';
|
||||||
|
|
||||||
const StyledChip = styled.div<{ variant: SortOrFitlerChipVariant }>`
|
const StyledChip = styled.div<{ variant: SortOrFilterChipVariant }>`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background-color: ${({ theme, variant }) => {
|
background-color: ${({ theme, variant }) => {
|
||||||
switch (variant) {
|
switch (variant) {
|
||||||
@ -55,7 +55,7 @@ const StyledIcon = styled.div`
|
|||||||
display: flex;
|
display: flex;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledDelete = styled.button<{ variant: SortOrFitlerChipVariant }>`
|
const StyledDelete = styled.button<{ variant: SortOrFilterChipVariant }>`
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
width: 20px;
|
width: 20px;
|
||||||
@ -89,12 +89,12 @@ const StyledLabelKey = styled.div`
|
|||||||
font-weight: ${({ theme }) => theme.font.weight.medium};
|
font-weight: ${({ theme }) => theme.font.weight.medium};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
type SortOrFitlerChipVariant = 'default' | 'danger';
|
export type SortOrFilterChipVariant = 'default' | 'danger';
|
||||||
|
|
||||||
type SortOrFilterChipProps = {
|
type SortOrFilterChipProps = {
|
||||||
labelKey?: string;
|
labelKey?: string;
|
||||||
labelValue: string;
|
labelValue: string;
|
||||||
variant?: SortOrFitlerChipVariant;
|
variant?: SortOrFilterChipVariant;
|
||||||
Icon?: IconComponent;
|
Icon?: IconComponent;
|
||||||
onRemove: () => void;
|
onRemove: () => void;
|
||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
|
|||||||
@ -13,7 +13,9 @@ import { EditableSortChip } from '@/views/components/EditableSortChip';
|
|||||||
import { ViewBarFilterEffect } from '@/views/components/ViewBarFilterEffect';
|
import { ViewBarFilterEffect } from '@/views/components/ViewBarFilterEffect';
|
||||||
import { useViewFromQueryParams } from '@/views/hooks/internal/useViewFromQueryParams';
|
import { useViewFromQueryParams } from '@/views/hooks/internal/useViewFromQueryParams';
|
||||||
|
|
||||||
|
import { useCheckIsSoftDeleteFilter } from '@/object-record/record-filter/hooks/useCheckIsSoftDeleteFilter';
|
||||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||||
|
import { SoftDeleteFilterChip } from '@/views/components/SoftDeleteFilterChip';
|
||||||
import { useApplyCurrentViewFiltersToCurrentRecordFilters } from '@/views/hooks/useApplyCurrentViewFiltersToCurrentRecordFilters';
|
import { useApplyCurrentViewFiltersToCurrentRecordFilters } from '@/views/hooks/useApplyCurrentViewFiltersToCurrentRecordFilters';
|
||||||
import { useAreViewFiltersDifferentFromRecordFilters } from '@/views/hooks/useAreViewFiltersDifferentFromRecordFilters';
|
import { useAreViewFiltersDifferentFromRecordFilters } from '@/views/hooks/useAreViewFiltersDifferentFromRecordFilters';
|
||||||
import { useAreViewSortsDifferentFromRecordSorts } from '@/views/hooks/useAreViewSortsDifferentFromRecordSorts';
|
import { useAreViewSortsDifferentFromRecordSorts } from '@/views/hooks/useAreViewSortsDifferentFromRecordSorts';
|
||||||
@ -22,8 +24,8 @@ import { useResetUnsavedViewStates } from '@/views/hooks/useResetUnsavedViewStat
|
|||||||
import { availableSortDefinitionsComponentState } from '@/views/states/availableSortDefinitionsComponentState';
|
import { availableSortDefinitionsComponentState } from '@/views/states/availableSortDefinitionsComponentState';
|
||||||
import { isViewBarExpandedComponentState } from '@/views/states/isViewBarExpandedComponentState';
|
import { isViewBarExpandedComponentState } from '@/views/states/isViewBarExpandedComponentState';
|
||||||
import { mapViewSortsToSorts } from '@/views/utils/mapViewSortsToSorts';
|
import { mapViewSortsToSorts } from '@/views/utils/mapViewSortsToSorts';
|
||||||
|
import { isNonEmptyArray } from '@sniptt/guards';
|
||||||
import { isDefined } from 'twenty-shared';
|
import { isDefined } from 'twenty-shared';
|
||||||
import { VariantFilterChip } from './VariantFilterChip';
|
|
||||||
|
|
||||||
export type ViewBarDetailsProps = {
|
export type ViewBarDetailsProps = {
|
||||||
hasFilterButton?: boolean;
|
hasFilterButton?: boolean;
|
||||||
@ -144,22 +146,19 @@ export const ViewBarDetails = ({
|
|||||||
viewSortsAreDifferentFromRecordSorts) &&
|
viewSortsAreDifferentFromRecordSorts) &&
|
||||||
!hasFiltersQueryParams;
|
!hasFiltersQueryParams;
|
||||||
|
|
||||||
const otherViewFilters = useMemo(() => {
|
const { checkIsSoftDeleteFilter } = useCheckIsSoftDeleteFilter();
|
||||||
return currentRecordFilters.filter(
|
|
||||||
(viewFilter) =>
|
|
||||||
viewFilter.variant &&
|
|
||||||
viewFilter.variant !== 'default' &&
|
|
||||||
!viewFilter.viewFilterGroupId,
|
|
||||||
);
|
|
||||||
}, [currentRecordFilters]);
|
|
||||||
|
|
||||||
const defaultViewFilters = useMemo(() => {
|
const softDeleteFilter = currentRecordFilters.find((recordFilter) =>
|
||||||
|
checkIsSoftDeleteFilter(recordFilter),
|
||||||
|
);
|
||||||
|
|
||||||
|
const recordFilters = useMemo(() => {
|
||||||
return currentRecordFilters.filter(
|
return currentRecordFilters.filter(
|
||||||
(viewFilter) =>
|
(recordFilter) =>
|
||||||
(!viewFilter.variant || viewFilter.variant === 'default') &&
|
!recordFilter.viewFilterGroupId &&
|
||||||
!viewFilter.viewFilterGroupId,
|
!checkIsSoftDeleteFilter(recordFilter),
|
||||||
);
|
);
|
||||||
}, [currentRecordFilters]);
|
}, [currentRecordFilters, checkIsSoftDeleteFilter]);
|
||||||
|
|
||||||
const { applyCurrentViewFiltersToCurrentRecordFilters } =
|
const { applyCurrentViewFiltersToCurrentRecordFilters } =
|
||||||
useApplyCurrentViewFiltersToCurrentRecordFilters();
|
useApplyCurrentViewFiltersToCurrentRecordFilters();
|
||||||
@ -190,45 +189,46 @@ export const ViewBarDetails = ({
|
|||||||
<StyledBar>
|
<StyledBar>
|
||||||
<StyledFilterContainer>
|
<StyledFilterContainer>
|
||||||
<StyledChipcontainer>
|
<StyledChipcontainer>
|
||||||
{otherViewFilters.map((viewFilter) => (
|
{isDefined(softDeleteFilter) && (
|
||||||
<VariantFilterChip
|
<SoftDeleteFilterChip
|
||||||
key={viewFilter.fieldMetadataId}
|
key={softDeleteFilter.fieldMetadataId}
|
||||||
recordFilter={viewFilter}
|
recordFilter={softDeleteFilter}
|
||||||
viewBarId={viewBarId}
|
viewBarId={viewBarId}
|
||||||
/>
|
/>
|
||||||
))}
|
)}
|
||||||
{!!otherViewFilters.length &&
|
{isDefined(softDeleteFilter) && (
|
||||||
!!currentViewWithCombinedFiltersAndSorts?.viewSorts?.length && (
|
<StyledSeperatorContainer>
|
||||||
<StyledSeperatorContainer>
|
<StyledSeperator />
|
||||||
<StyledSeperator />
|
</StyledSeperatorContainer>
|
||||||
</StyledSeperatorContainer>
|
)}
|
||||||
)}
|
|
||||||
{mapViewSortsToSorts(
|
{mapViewSortsToSorts(
|
||||||
currentViewWithCombinedFiltersAndSorts?.viewSorts ?? [],
|
currentViewWithCombinedFiltersAndSorts?.viewSorts ?? [],
|
||||||
availableSortDefinitions,
|
availableSortDefinitions,
|
||||||
).map((sort) => (
|
).map((sort) => (
|
||||||
<EditableSortChip key={sort.fieldMetadataId} viewSort={sort} />
|
<EditableSortChip key={sort.fieldMetadataId} viewSort={sort} />
|
||||||
))}
|
))}
|
||||||
{!!currentViewWithCombinedFiltersAndSorts?.viewSorts?.length &&
|
{isNonEmptyArray(recordFilters) &&
|
||||||
!!defaultViewFilters.length && (
|
isNonEmptyArray(
|
||||||
|
currentViewWithCombinedFiltersAndSorts?.viewSorts,
|
||||||
|
) && (
|
||||||
<StyledSeperatorContainer>
|
<StyledSeperatorContainer>
|
||||||
<StyledSeperator />
|
<StyledSeperator />
|
||||||
</StyledSeperatorContainer>
|
</StyledSeperatorContainer>
|
||||||
)}
|
)}
|
||||||
{showAdvancedFilterDropdownButton && <AdvancedFilterDropdownButton />}
|
{showAdvancedFilterDropdownButton && <AdvancedFilterDropdownButton />}
|
||||||
{defaultViewFilters.map((viewFilter) => (
|
{recordFilters.map((recordFilter) => (
|
||||||
<ObjectFilterDropdownComponentInstanceContext.Provider
|
<ObjectFilterDropdownComponentInstanceContext.Provider
|
||||||
key={viewFilter.id}
|
key={recordFilter.id}
|
||||||
value={{ instanceId: viewFilter.id }}
|
value={{ instanceId: recordFilter.id }}
|
||||||
>
|
>
|
||||||
<DropdownScope dropdownScopeId={viewFilter.id}>
|
<DropdownScope dropdownScopeId={recordFilter.id}>
|
||||||
<ViewBarFilterEffect filterDropdownId={viewFilter.id} />
|
<ViewBarFilterEffect filterDropdownId={recordFilter.id} />
|
||||||
<EditableFilterDropdownButton
|
<EditableFilterDropdownButton
|
||||||
viewFilter={viewFilter}
|
viewFilter={recordFilter}
|
||||||
hotkeyScope={{
|
hotkeyScope={{
|
||||||
scope: viewFilter.id,
|
scope: recordFilter.id,
|
||||||
}}
|
}}
|
||||||
viewFilterDropdownId={viewFilter.id}
|
viewFilterDropdownId={recordFilter.id}
|
||||||
/>
|
/>
|
||||||
</DropdownScope>
|
</DropdownScope>
|
||||||
</ObjectFilterDropdownComponentInstanceContext.Provider>
|
</ObjectFilterDropdownComponentInstanceContext.Provider>
|
||||||
|
|||||||
Reference in New Issue
Block a user