mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-16 17:46:45 +00:00
feat(Data Table Node): Show 'Is False' / 'Is True' condition on boolean columns (no-changelog) (#19478)
This commit is contained in:
@@ -10,7 +10,7 @@ export type FilterType = typeof ANY_CONDITION | typeof ALL_CONDITIONS;
|
||||
export type FieldEntry =
|
||||
| {
|
||||
keyName: string;
|
||||
condition: 'isEmpty' | 'isNotEmpty';
|
||||
condition: 'isEmpty' | 'isNotEmpty' | 'isTrue' | 'isFalse';
|
||||
}
|
||||
| {
|
||||
keyName: string;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import type {
|
||||
ILoadOptionsFunctions,
|
||||
INodeListSearchResult,
|
||||
INodePropertyOptions,
|
||||
ResourceMapperField,
|
||||
ResourceMapperFields,
|
||||
import {
|
||||
type ILoadOptionsFunctions,
|
||||
type INodeListSearchResult,
|
||||
type INodePropertyOptions,
|
||||
type ResourceMapperField,
|
||||
type ResourceMapperFields,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import { getDataTableAggregateProxy, getDataTableProxyLoadOptions } from './utils';
|
||||
@@ -80,14 +80,21 @@ export async function getConditionsForColumn(this: ILoadOptionsFunctions) {
|
||||
}
|
||||
const keyName = this.getCurrentNodeParameter('&keyName') as string;
|
||||
|
||||
// Base conditions available for all column types
|
||||
const baseConditions: INodePropertyOptions[] = [
|
||||
{ name: 'Equals', value: 'eq' },
|
||||
{ name: 'Not Equals', value: 'neq' },
|
||||
const nullConditions: INodePropertyOptions[] = [
|
||||
{ name: 'Is Empty', value: 'isEmpty' },
|
||||
{ name: 'Is Not Empty', value: 'isNotEmpty' },
|
||||
];
|
||||
|
||||
const equalsConditions: INodePropertyOptions[] = [
|
||||
{ name: 'Equals', value: 'eq' },
|
||||
{ name: 'Not Equals', value: 'neq' },
|
||||
];
|
||||
|
||||
const booleanConditions: INodePropertyOptions[] = [
|
||||
{ name: 'Is True', value: 'isTrue' },
|
||||
{ name: 'Is False', value: 'isFalse' },
|
||||
];
|
||||
|
||||
const comparableConditions: INodePropertyOptions[] = [
|
||||
{ name: 'Greater Than', value: 'gt' },
|
||||
{ name: 'Greater Than or Equal', value: 'gte' },
|
||||
@@ -100,7 +107,13 @@ export async function getConditionsForColumn(this: ILoadOptionsFunctions) {
|
||||
{ name: 'Contains (Case-Insensitive)', value: 'ilike' },
|
||||
];
|
||||
|
||||
const allConditions = [...baseConditions, ...comparableConditions, ...stringConditions];
|
||||
const allConditions = [
|
||||
...nullConditions,
|
||||
...equalsConditions,
|
||||
...booleanConditions,
|
||||
...comparableConditions,
|
||||
...stringConditions,
|
||||
];
|
||||
|
||||
// If no column is selected yet, return all conditions
|
||||
if (!keyName) {
|
||||
@@ -113,20 +126,28 @@ export async function getConditionsForColumn(this: ILoadOptionsFunctions) {
|
||||
(await proxy.getColumns()).find((col) => col.name === keyName);
|
||||
|
||||
if (!column) {
|
||||
return baseConditions;
|
||||
return [...equalsConditions, ...nullConditions];
|
||||
}
|
||||
|
||||
const conditions = baseConditions;
|
||||
const conditions: INodePropertyOptions[] = [];
|
||||
|
||||
if (column.type === 'boolean') {
|
||||
conditions.push.apply(conditions, booleanConditions);
|
||||
}
|
||||
|
||||
// String columns get LIKE operators
|
||||
if (column.type === 'string') {
|
||||
conditions.push.apply(conditions, equalsConditions);
|
||||
conditions.push.apply(conditions, stringConditions);
|
||||
}
|
||||
|
||||
if (['number', 'date', 'string'].includes(column.type)) {
|
||||
conditions.push.apply(conditions, equalsConditions);
|
||||
conditions.push.apply(conditions, comparableConditions);
|
||||
}
|
||||
|
||||
conditions.push.apply(conditions, nullConditions);
|
||||
|
||||
return conditions;
|
||||
}
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ export function getSelectFields(
|
||||
default: '',
|
||||
displayOptions: {
|
||||
hide: {
|
||||
condition: ['isEmpty', 'isNotEmpty'],
|
||||
condition: ['isEmpty', 'isNotEmpty', 'isTrue', 'isFalse'],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -101,6 +101,18 @@ export function buildGetManyFilter(
|
||||
condition: 'neq' as const,
|
||||
value: null,
|
||||
};
|
||||
case 'isTrue':
|
||||
return {
|
||||
columnName: x.keyName,
|
||||
condition: 'eq' as const,
|
||||
value: true,
|
||||
};
|
||||
case 'isFalse':
|
||||
return {
|
||||
columnName: x.keyName,
|
||||
condition: 'eq' as const,
|
||||
value: false,
|
||||
};
|
||||
default:
|
||||
return {
|
||||
columnName: x.keyName,
|
||||
|
||||
@@ -203,9 +203,12 @@ describe('dataObjectToApiInput', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('buildGetManyFilter - isEmpty/isNotEmpty translation', () => {
|
||||
describe('buildGetManyFilter', () => {
|
||||
describe('isEmpty/isNotEmpty translation', () => {
|
||||
it('should translate isEmpty to eq with null value', () => {
|
||||
const fieldEntries = [{ keyName: 'name', condition: 'isEmpty' as const, keyValue: 'ignored' }];
|
||||
const fieldEntries = [
|
||||
{ keyName: 'name', condition: 'isEmpty' as const, keyValue: 'ignored' },
|
||||
];
|
||||
|
||||
const result = buildGetManyFilter(fieldEntries, ALL_CONDITIONS);
|
||||
|
||||
@@ -270,8 +273,80 @@ describe('buildGetManyFilter - isEmpty/isNotEmpty translation', () => {
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should preserve existing conditions unchanged', () => {
|
||||
describe('isTrue/isFalse translation', () => {
|
||||
it('should translate isTrue to eq with true value', () => {
|
||||
const fieldEntries = [
|
||||
{ keyName: 'isActive', condition: 'isTrue' as const, keyValue: 'ignored' },
|
||||
];
|
||||
|
||||
const result = buildGetManyFilter(fieldEntries, ALL_CONDITIONS);
|
||||
|
||||
expect(result).toEqual({
|
||||
type: 'and',
|
||||
filters: [
|
||||
{
|
||||
columnName: 'isActive',
|
||||
condition: 'eq',
|
||||
value: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it('should translate isFalse to eq with false value', () => {
|
||||
const fieldEntries = [
|
||||
{ keyName: 'email', condition: 'isFalse' as const, keyValue: 'ignored' },
|
||||
];
|
||||
|
||||
const result = buildGetManyFilter(fieldEntries, ANY_CONDITION);
|
||||
|
||||
expect(result).toEqual({
|
||||
type: 'or',
|
||||
filters: [
|
||||
{
|
||||
columnName: 'email',
|
||||
condition: 'eq',
|
||||
value: false,
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle mixed conditions including isTrue/isFalse', () => {
|
||||
const fieldEntries = [
|
||||
{ keyName: 'name', condition: 'eq' as const, keyValue: 'John' },
|
||||
{ keyName: 'isActive', condition: 'isTrue' as const, keyValue: 'ignored' },
|
||||
{ keyName: 'isDeleted', condition: 'isFalse' as const, keyValue: 'ignored' },
|
||||
];
|
||||
|
||||
const result = buildGetManyFilter(fieldEntries, ALL_CONDITIONS);
|
||||
|
||||
expect(result).toEqual({
|
||||
type: 'and',
|
||||
filters: [
|
||||
{
|
||||
columnName: 'name',
|
||||
condition: 'eq',
|
||||
value: 'John',
|
||||
},
|
||||
{
|
||||
columnName: 'isActive',
|
||||
condition: 'eq',
|
||||
value: true,
|
||||
},
|
||||
{
|
||||
columnName: 'isDeleted',
|
||||
condition: 'eq',
|
||||
value: false,
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle other conditions', () => {
|
||||
const fieldEntries = [
|
||||
{ keyName: 'age', condition: 'gt' as const, keyValue: 18 },
|
||||
{ keyName: 'name', condition: 'like' as const, keyValue: '%john%' },
|
||||
|
||||
Reference in New Issue
Block a user