[Feat] : add source to actor fields (#18118)

fixes #18099 

Simple implementation of the matchingSourceValues to be searched in the
ACTOR case in turnRecordFilterIntoRecordGqlOperationFilter

<img width="1239" height="494" alt="Screenshot 2026-02-20 at 5 21 14 PM"
src="https://github.com/user-attachments/assets/20ee076e-dccd-4747-a1ab-38d649f6591e"
/>

---------

Co-authored-by: Arun kumar <arunkumar@Aruns-MacBook-Air.local>
Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
This commit is contained in:
Arun
2026-03-10 18:38:18 +05:30
committed by GitHub
parent 59e9563fc7
commit 1656bb5568
7 changed files with 154 additions and 9 deletions
@@ -2,8 +2,8 @@ import {
FieldMetadataType,
ViewFilterOperand as RecordFilterOperand,
} from '@/types';
import { turnRecordFilterIntoRecordGqlOperationFilter } from '@/utils/filter/turnRecordFilterIntoGqlOperationFilter';
import { type RecordFilter } from '@/utils';
import { turnRecordFilterIntoRecordGqlOperationFilter } from '@/utils/filter/turnRecordFilterIntoGqlOperationFilter';
const fields = [
{ id: 'f-text', name: 'name', type: FieldMetadataType.TEXT, label: 'Name' },
@@ -709,18 +709,114 @@ describe('turnRecordFilterIntoRecordGqlOperationFilter', () => {
});
describe('ACTOR filter', () => {
it('should handle CONTAINS operand', () => {
it('should handle CONTAINS with a value matching a source - includes source in filter', () => {
const result = turnRecordFilterIntoRecordGqlOperationFilter({
filterValueDependencies,
recordFilter: makeFilter(
'f-actor',
RecordFilterOperand.CONTAINS,
'Admin',
'api',
),
fieldMetadataItems: fields,
});
expect(result).toBeDefined();
expect(result).toEqual({
or: [
{
actor: {
name: { ilike: '%api%' },
},
},
{
actor: {
source: { in: ['API'] },
},
},
],
});
});
it('should handle CONTAINS with no matching source - no empty {} or [] in filter', () => {
const result = turnRecordFilterIntoRecordGqlOperationFilter({
filterValueDependencies,
recordFilter: makeFilter(
'f-actor',
RecordFilterOperand.CONTAINS,
'xyz123',
),
fieldMetadataItems: fields,
});
expect(result).toEqual({
or: [
{
actor: {
name: { ilike: '%xyz123%' },
},
},
],
});
const json = JSON.stringify(result);
expect(json).not.toContain('[]');
expect(json).not.toContain('{}');
});
it('should handle DOES_NOT_CONTAIN with a value matching a source - includes not source in filter', () => {
const result = turnRecordFilterIntoRecordGqlOperationFilter({
filterValueDependencies,
recordFilter: makeFilter(
'f-actor',
RecordFilterOperand.DOES_NOT_CONTAIN,
'api',
),
fieldMetadataItems: fields,
});
expect(result).toEqual({
and: [
{
not: {
actor: {
name: { ilike: '%api%' },
},
},
},
{
not: {
actor: {
source: { in: ['API'] },
},
},
},
],
});
});
it('should handle DOES_NOT_CONTAIN with no matching source - no empty {} or [] in filter', () => {
const result = turnRecordFilterIntoRecordGqlOperationFilter({
filterValueDependencies,
recordFilter: makeFilter(
'f-actor',
RecordFilterOperand.DOES_NOT_CONTAIN,
'xyz123',
),
fieldMetadataItems: fields,
});
expect(result).toEqual({
and: [
{
not: {
actor: {
name: { ilike: '%xyz123%' },
},
},
},
],
});
const json = JSON.stringify(result);
expect(json).not.toContain('[]');
expect(json).not.toContain('{}');
});
});
@@ -2,6 +2,7 @@ import { isNonEmptyString } from '@sniptt/guards';
import { Temporal } from 'temporal-polyfill';
import {
FieldActorSource,
FieldMetadataType,
ViewFilterOperand as RecordFilterOperand,
type ActorFilter,
@@ -1218,8 +1219,13 @@ export const turnRecordFilterIntoRecordGqlOperationFilter = ({
}
}
const matchingSourceValues = Object.values(FieldActorSource).filter(
(actorSource) =>
actorSource.toLowerCase().includes(recordFilter.value.toLowerCase()),
);
switch (recordFilter.operand) {
case RecordFilterOperand.CONTAINS:
case RecordFilterOperand.CONTAINS: {
return {
or: [
{
@@ -1229,9 +1235,21 @@ export const turnRecordFilterIntoRecordGqlOperationFilter = ({
},
} satisfies ActorFilter,
},
...(matchingSourceValues.length > 0
? [
{
[correspondingFieldMetadataItem.name]: {
source: {
in: matchingSourceValues,
},
} satisfies ActorFilter,
},
]
: []),
],
};
case RecordFilterOperand.DOES_NOT_CONTAIN:
}
case RecordFilterOperand.DOES_NOT_CONTAIN: {
return {
and: [
{
@@ -1243,8 +1261,22 @@ export const turnRecordFilterIntoRecordGqlOperationFilter = ({
} satisfies ActorFilter,
},
},
...(matchingSourceValues.length > 0
? [
{
not: {
[correspondingFieldMetadataItem.name]: {
source: {
in: matchingSourceValues,
},
} satisfies ActorFilter,
},
},
]
: []),
],
};
}
default: {
const fieldForRecordFilter = fieldMetadataItems.find(
(field) => field.id === recordFilter.fieldMetadataId,