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:
@ -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';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -7,4 +7,5 @@ export const TEXT_FILTER_TYPES = [
|
|||||||
'LINKS',
|
'LINKS',
|
||||||
'ARRAY',
|
'ARRAY',
|
||||||
'RAW_JSON',
|
'RAW_JSON',
|
||||||
|
'UUID',
|
||||||
];
|
];
|
||||||
|
|||||||
@ -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];
|
||||||
|
|||||||
@ -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');
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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}`);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
@ -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
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user