Add basic UUID support to filters (#12676)

- Only operands IS
- Do not set filter when no valid uuids or variables
- Allow ID field to be filterable despite being system



https://github.com/user-attachments/assets/e1c67103-728f-4798-91c6-4aea162f8698

---------

Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
This commit is contained in:
Thomas Trompette
2025-06-17 14:58:50 +02:00
committed by GitHub
parent 01a69f6288
commit fb9d5066dc
9 changed files with 59 additions and 2 deletions

View File

@ -51,6 +51,8 @@ export const getFilterTypeFromFieldType = (
return 'BOOLEAN'; return 'BOOLEAN';
case FieldMetadataType.TS_VECTOR: case FieldMetadataType.TS_VECTOR:
return 'TS_VECTOR'; return 'TS_VECTOR';
case FieldMetadataType.UUID:
return 'UUID';
default: default:
return 'TEXT'; return 'TEXT';
} }

View File

@ -9,6 +9,7 @@ export const getFilterFilterableFieldMetadataItems = ({
return (field: FieldMetadataItem) => { return (field: FieldMetadataItem) => {
const isSystemField = field.isSystem; const isSystemField = field.isSystem;
const isFieldActive = field.isActive; const isFieldActive = field.isActive;
const isIdField = field.name === 'id';
const isRelationFieldHandled = !( const isRelationFieldHandled = !(
field.type === FieldMetadataType.RELATION && field.type === FieldMetadataType.RELATION &&
@ -33,11 +34,12 @@ export const getFilterFilterableFieldMetadataItems = ({
FieldMetadataType.ACTOR, FieldMetadataType.ACTOR,
FieldMetadataType.PHONES, FieldMetadataType.PHONES,
FieldMetadataType.ARRAY, FieldMetadataType.ARRAY,
FieldMetadataType.UUID,
...(isJsonFilterEnabled ? [FieldMetadataType.RAW_JSON] : []), ...(isJsonFilterEnabled ? [FieldMetadataType.RAW_JSON] : []),
].includes(field.type); ].includes(field.type);
const isFieldFilterable = const isFieldFilterable =
!isSystemField && (!isSystemField || isIdField) &&
isFieldActive && isFieldActive &&
isRelationFieldHandled && isRelationFieldHandled &&
isFieldTypeFilterable; isFieldTypeFilterable;

View File

@ -7,4 +7,5 @@ export const TEXT_FILTER_TYPES = [
'LINKS', 'LINKS',
'ARRAY', 'ARRAY',
'RAW_JSON', 'RAW_JSON',
'UUID',
]; ];

View File

@ -20,6 +20,7 @@ export const FILTERABLE_FIELD_TYPES = [
'ARRAY', 'ARRAY',
'RAW_JSON', 'RAW_JSON',
'BOOLEAN', 'BOOLEAN',
'UUID',
] as const; ] as const;
type FilterableFieldTypeBaseLiteral = (typeof FILTERABLE_FIELD_TYPES)[number]; type FilterableFieldTypeBaseLiteral = (typeof FILTERABLE_FIELD_TYPES)[number];

View File

@ -17,6 +17,7 @@ import {
SelectFilter, SelectFilter,
StringFilter, StringFilter,
TSVectorFilter, TSVectorFilter,
UUIDFilter,
} from '@/object-record/graphql/types/RecordGqlOperationFilter'; } from '@/object-record/graphql/types/RecordGqlOperationFilter';
import { Field } from '~/generated/graphql'; import { Field } from '~/generated/graphql';
import { generateILikeFiltersForCompositeFields } from '~/utils/array/generateILikeFiltersForCompositeFields'; import { generateILikeFiltersForCompositeFields } from '~/utils/array/generateILikeFiltersForCompositeFields';
@ -1176,6 +1177,24 @@ export const turnRecordFilterIntoRecordGqlOperationFilter = ({
} as BooleanFilter, } as BooleanFilter,
}; };
} }
case 'UUID': {
const recordIds = arrayOfUuidOrVariableSchema.parse(recordFilter.value);
if (recordIds.length === 0) return;
switch (recordFilter.operand) {
case RecordFilterOperand.Is:
return {
[correspondingFieldMetadataItem.name]: {
in: recordIds,
} as UUIDFilter,
};
default:
throw new Error(
`Unknown operand ${recordFilter.operand} for ${filterType} filter`,
);
}
}
default: default:
throw new Error('Unknown filter type'); throw new Error('Unknown filter type');
} }

View File

@ -128,6 +128,7 @@ export const FILTER_OPERANDS_MAP = {
], ],
BOOLEAN: [RecordFilterOperand.Is], BOOLEAN: [RecordFilterOperand.Is],
TS_VECTOR: [RecordFilterOperand.VectorSearch], TS_VECTOR: [RecordFilterOperand.VectorSearch],
UUID: [RecordFilterOperand.Is],
} as const satisfies FilterOperandMap; } as const satisfies FilterOperandMap;
export const COMPOSITE_FIELD_FILTER_OPERANDS_MAP = { export const COMPOSITE_FIELD_FILTER_OPERANDS_MAP = {
@ -204,6 +205,8 @@ export const getRecordFilterOperands = ({
return FILTER_OPERANDS_MAP.BOOLEAN; return FILTER_OPERANDS_MAP.BOOLEAN;
case 'TS_VECTOR': case 'TS_VECTOR':
return FILTER_OPERANDS_MAP.TS_VECTOR; return FILTER_OPERANDS_MAP.TS_VECTOR;
case 'UUID':
return FILTER_OPERANDS_MAP.UUID;
default: default:
assertUnreachable(filterType, `Unknown filter type ${filterType}`); assertUnreachable(filterType, `Unknown filter type ${filterType}`);
} }

View File

@ -497,4 +497,15 @@ describe('buildValueFromFilter', () => {
expect(buildValueFromFilter({ filter })).toBeUndefined(); expect(buildValueFromFilter({ filter })).toBeUndefined();
}); });
}); });
describe('UUID field type', () => {
it('should return the value', () => {
const filter = createTestFilter(
ViewFilterOperand.Is,
'test-uuid',
'UUID',
);
expect(buildValueFromFilter({ filter })).toBe('test-uuid');
});
});
}); });

View File

@ -96,6 +96,11 @@ export const buildValueFromFilter = ({
label, label,
); );
} }
case 'UUID':
return computeValueFromFilterUUID(
filter.operand as (typeof FILTER_OPERANDS_MAP)['UUID'][number],
filter.value,
);
default: default:
assertUnreachable(filter.type); assertUnreachable(filter.type);
} }
@ -310,3 +315,15 @@ const computeValueFromFilterTSVector = (
assertUnreachable(operand); assertUnreachable(operand);
} }
}; };
const computeValueFromFilterUUID = (
operand: RecordFilterToRecordInputOperand<'UUID'>,
value: string,
) => {
switch (operand) {
case ViewFilterOperand.Is:
return value;
default:
assertUnreachable(operand);
}
};

View File

@ -34,6 +34,7 @@ export const shouldDisplayFormField = ({
actionType: WorkflowActionType; actionType: WorkflowActionType;
}) => { }) => {
let isTypeAllowedForAction = false; let isTypeAllowedForAction = false;
const isIdField = fieldMetadataItem.name === 'id';
switch (actionType) { switch (actionType) {
case 'CREATE_RECORD': case 'CREATE_RECORD':
@ -57,7 +58,7 @@ export const shouldDisplayFormField = ({
return ( return (
isTypeAllowedForAction && isTypeAllowedForAction &&
!fieldMetadataItem.isSystem && (!fieldMetadataItem.isSystem || isIdField) &&
fieldMetadataItem.isActive fieldMetadataItem.isActive
); );
}; };