diff --git a/gerbil-manager-web/e2e/mock-api.ts b/gerbil-manager-web/e2e/mock-api.ts index ea19acb..6219a76 100644 --- a/gerbil-manager-web/e2e/mock-api.ts +++ b/gerbil-manager-web/e2e/mock-api.ts @@ -27,7 +27,10 @@ function matchesFilter(row: Row, filter: string | null): boolean { if (!filter) return true return filter.split(',').every((andPart) => andPart.split('|').some((cond) => { - let m = cond.match(/^(\w+)=\*(.*)\*(\/i)?$/) + // Gridify "contains": `field=*value` — value runs to the end (optionally /i). + // Mirror the REAL backend: no trailing `*` (the old `=\*(.*)\*` regex hid the + // SQL-LIKE `name=*a*` bug that returned 0 rows against real Gridify). + let m = cond.match(/^(\w+)=\*(.*?)(\/i)?$/) if (m) { return String(row[m[1]] ?? '') .toLowerCase() diff --git a/gerbil-manager-web/src/api/gridify.ts b/gerbil-manager-web/src/api/gridify.ts index cce4f66..cbb1c0c 100644 --- a/gerbil-manager-web/src/api/gridify.ts +++ b/gerbil-manager-web/src/api/gridify.ts @@ -43,9 +43,12 @@ export interface FilterCondition { export function condition(c: FilterCondition): string { const escaped = escapeGridifyValue(String(c.value)) if (c.op === 'contains') { - // Gridify "contains" operator is =* ; default to case-insensitive. + // Gridify's "contains" operator is `=*` — the value follows directly and is + // matched as a substring. Do NOT wrap the value in asterisks (SQL-LIKE habit): + // a trailing `*` is a literal character to Gridify, so `name=*a*` searches for + // the literal "a*" and matches nothing. Correct form: `name=*a`. const suffix = c.caseInsensitive === false ? '' : '/i' - return `${c.field}=*${escaped}*${suffix}` + return `${c.field}=*${escaped}${suffix}` } // Gridify's equals operator is a single '='; callers use '==' semantically. const op = c.op === '==' ? '=' : c.op