Fix kanban view when grouping select field has null value (#16998)
This commit is contained in:
+54
@@ -0,0 +1,54 @@
|
||||
import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { computeRecordGroupOptionsFilter } from '@/object-record/record-group/utils/computeRecordGroupOptionsFilter';
|
||||
|
||||
const mockFieldMetadata = {
|
||||
id: 'field-1',
|
||||
name: 'status',
|
||||
} as FieldMetadataItem;
|
||||
|
||||
describe('computeRecordGroupOptionsFilter', () => {
|
||||
it('should return empty object when recordGroupFieldMetadata is undefined', () => {
|
||||
const result = computeRecordGroupOptionsFilter({
|
||||
recordGroupFieldMetadata: undefined,
|
||||
recordGroupValues: ['value1', 'value2'],
|
||||
});
|
||||
|
||||
expect(result).toEqual({});
|
||||
});
|
||||
|
||||
it('should return empty object when recordGroupFieldMetadata is null', () => {
|
||||
const result = computeRecordGroupOptionsFilter({
|
||||
recordGroupFieldMetadata: null,
|
||||
recordGroupValues: ['value1', 'value2'],
|
||||
});
|
||||
|
||||
expect(result).toEqual({});
|
||||
});
|
||||
|
||||
it('should return simple IN filter when no null values present', () => {
|
||||
const result = computeRecordGroupOptionsFilter({
|
||||
recordGroupFieldMetadata: mockFieldMetadata,
|
||||
recordGroupValues: ['value1', 'value2', 'value3'],
|
||||
});
|
||||
|
||||
expect(result).toEqual({
|
||||
status: {
|
||||
in: ['value1', 'value2', 'value3'],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should return OR filter with IS NULL when null value is present', () => {
|
||||
const result = computeRecordGroupOptionsFilter({
|
||||
recordGroupFieldMetadata: mockFieldMetadata,
|
||||
recordGroupValues: ['value1', null, 'value2'],
|
||||
});
|
||||
|
||||
expect(result).toEqual({
|
||||
or: [
|
||||
{ status: { is: 'NULL' } },
|
||||
{ status: { in: ['value1', 'value2'] } },
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
import { isNull } from '@sniptt/guards';
|
||||
import { type RecordGqlOperationFilter } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { type RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition';
|
||||
|
||||
export const computeRecordGroupOptionsFilter = ({
|
||||
recordGroupFieldMetadata,
|
||||
recordGroupValues,
|
||||
}: {
|
||||
recordGroupFieldMetadata: FieldMetadataItem | null | undefined;
|
||||
recordGroupValues: RecordGroupDefinition['value'][];
|
||||
}): RecordGqlOperationFilter => {
|
||||
if (!isDefined(recordGroupFieldMetadata) || recordGroupValues.length === 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const fieldName = recordGroupFieldMetadata.name;
|
||||
const hasNullValue = recordGroupValues.some(isNull);
|
||||
const nonNullValues = recordGroupValues.filter(
|
||||
(value): value is NonNullable<typeof value> => !isNull(value),
|
||||
);
|
||||
|
||||
return hasNullValue
|
||||
? {
|
||||
or: [
|
||||
{ [fieldName]: { is: 'NULL' } },
|
||||
...(nonNullValues.length > 0
|
||||
? [{ [fieldName]: { in: nonNullValues } }]
|
||||
: []),
|
||||
],
|
||||
}
|
||||
: nonNullValues.length > 0
|
||||
? {
|
||||
[fieldName]: { in: recordGroupValues },
|
||||
}
|
||||
: {};
|
||||
};
|
||||
+5
-8
@@ -5,6 +5,7 @@ import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/
|
||||
import { anyFieldFilterValueComponentState } from '@/object-record/record-filter/states/anyFieldFilterValueComponentState';
|
||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||
import { recordGroupDefinitionsComponentSelector } from '@/object-record/record-group/states/selectors/recordGroupDefinitionsComponentSelector';
|
||||
import { computeRecordGroupOptionsFilter } from '@/object-record/record-group/utils/computeRecordGroupOptionsFilter';
|
||||
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||
import { recordIndexGroupFieldMetadataItemComponentState } from '@/object-record/record-index/states/recordIndexGroupFieldMetadataComponentState';
|
||||
import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState';
|
||||
@@ -12,7 +13,6 @@ import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/ho
|
||||
import {
|
||||
combineFilters,
|
||||
computeRecordGqlOperationFilter,
|
||||
isDefined,
|
||||
turnAnyFieldFilterIntoRecordGqlFilter,
|
||||
} from 'twenty-shared/utils';
|
||||
|
||||
@@ -73,13 +73,10 @@ export const useRecordIndexGroupCommonQueryVariables = () => {
|
||||
(recordGroupDefinition) => recordGroupDefinition.value,
|
||||
);
|
||||
|
||||
const recordGroupOptionsFilter = isDefined(recordGroupFieldMetadata)
|
||||
? {
|
||||
[recordGroupFieldMetadata.name]: {
|
||||
in: recordGroupValues,
|
||||
},
|
||||
}
|
||||
: {};
|
||||
const recordGroupOptionsFilter = computeRecordGroupOptionsFilter({
|
||||
recordGroupFieldMetadata,
|
||||
recordGroupValues,
|
||||
});
|
||||
|
||||
const combinedFilters = combineFilters([
|
||||
anyFieldFilter,
|
||||
|
||||
Reference in New Issue
Block a user