From 15e5acfc7ee723bcb863cba58b8d2ba2e411dd3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Barfleur?= <39409397+kevinbarfleur@users.noreply.github.com> Date: Fri, 24 Jul 2026 04:47:28 +0200 Subject: [PATCH] WW-5645: exclude empty strings in text is-empty/is-not-empty collection filters --- src/helpers/filters.js | 24 ++++++++++++++++++++++-- ww-config.js | 6 ++++-- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/helpers/filters.js b/src/helpers/filters.js index 7d43320..cf47ccc 100644 --- a/src/helpers/filters.js +++ b/src/helpers/filters.js @@ -1,5 +1,5 @@ export function convertCondition({ field, operator, value, isEmptyIgnored }) { - if (isEmptyIgnored && !value) return []; + if (isEmptyIgnored && !isValuelessOperator(operator) && isEmptyValue(value)) return []; switch (operator) { case '$eq': return [field, 'eq', typeof value === 'string' ? `"${escape(value)}"` : value]; @@ -25,6 +25,10 @@ export function convertCondition({ field, operator, value, isEmptyIgnored }) { return [field, 'is', 'null']; case '$ne:null': return [field, 'not.is', 'null']; + case '$eq:null:text': + return `or(${field}.is.null,${field}.eq."")`; + case '$ne:null:text': + return `and(${field}.not.is.null,${field}.neq."")`; case '$in': return [field, 'in', `(${value})`]; case '$notIn': @@ -45,7 +49,9 @@ export function generateFilter(config) { if (!config.link || !config.conditions || config.if === false) return ''; const conditions = config.conditions .map(condition => { - return condition.link ? generateFilter(condition) : convertCondition(condition).join('.'); + if (condition.link) return generateFilter(condition); + const converted = convertCondition(condition); + return typeof converted === 'string' ? converted : converted.join('.'); }) .filter(condition => condition); @@ -60,3 +66,17 @@ function escape(value) { // weird but it's how back slash match return value.replaceAll('\\', '\\\\\\\\').replaceAll('"', '\\"'); } + +function isValuelessOperator(operator) { + return typeof operator === 'string' && operator.includes(':null'); +} + +function isEmptyValue(value) { + return ( + value === undefined || + value === null || + value === '' || + (Array.isArray(value) && value.length === 0) || + (typeof value === 'object' && JSON.stringify(value) === '{}') + ); +} diff --git a/ww-config.js b/ww-config.js index d9b2ff7..19a22bb 100644 --- a/ww-config.js +++ b/ww-config.js @@ -76,11 +76,13 @@ export default { }, { label: 'Ends with', value: '$iLike:endsWith', acceptedTypes: ['string'], defaultValue: 'end' }, { label: 'Is exactly', value: '$eq', acceptedTypes: ['array', 'object'] }, - { label: 'Is empty', value: '$eq:null', acceptedTypes: ['string', 'number', 'array', 'object'] }, + { label: 'Is empty', value: '$eq:null:text', acceptedTypes: ['string'] }, + { label: 'Is not empty', value: '$ne:null:text', acceptedTypes: ['string'] }, + { label: 'Is empty', value: '$eq:null', acceptedTypes: ['number', 'array', 'object'] }, { label: 'Is not empty', value: '$ne:null', - acceptedTypes: ['string', 'number', 'array', 'object'], + acceptedTypes: ['number', 'array', 'object'], }, { label: 'Is in', value: '$in', acceptedTypes: ['string', 'number'], defaultValue: [] }, { label: 'Is not in', value: '$notIn', acceptedTypes: ['string', 'number'], defaultValue: [] },