From d559bb2620eb292e4421e575e73b3018f5d0d7ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20Mr=C3=B3=C5=BA?= <78143552+adrianmroz-allegro@users.noreply.github.com> Date: Mon, 13 Feb 2023 12:50:05 +0100 Subject: [PATCH] Bugfix/add ignore case option for string filters (#1032) * Add ignoreCase option for string filter clause * pinboard and string filter menu search boxes should ignore case for better UX * change fixtures so they include default ignorCase value in results --- cypress/e2e/mkurl.cy.ts | 2 +- .../pinboard-tile/pinboard-tile.tsx | 3 ++- .../selectable-string-filter-menu.tsx | 3 ++- .../models/filter-clause/filter-clause.ts | 18 ++++++++++--- .../url-hash-converter.fixtures.ts | 25 ++++++++++--------- .../version-4/filter-definition.fixtures.ts | 5 ++-- .../version-4/filter-definition.ts | 9 ++++--- 7 files changed, 41 insertions(+), 24 deletions(-) diff --git a/cypress/e2e/mkurl.cy.ts b/cypress/e2e/mkurl.cy.ts index 12a1d80d2..212568739 100644 --- a/cypress/e2e/mkurl.cy.ts +++ b/cypress/e2e/mkurl.cy.ts @@ -46,7 +46,7 @@ context("mkurl", () => { cy.request("POST", "http://localhost:9090/mkurl", body).then((hash: Cypress.Response) => { expect(hash.status).to.eq(200); - expect(hash.body.hash).to.eq("#wiki/4/N4IgbglgzgrghgGwgLzgFwgewHYgFwhpwBGCApiADTjTxKoY4DKZaG2A5lPqAMaYIEcAA5QyAJUwB3bngBmiMQF9qGALZlkOCgQCiaXgHoAqgBUAwlRByICNGQBOsgNqg0AT2E7CEDVYdkcvg+fqq+EnCcZC6gUEQOaMEATAAMAIwArAC0KQCcWWlJpikpeCVlKQB0JSkAWlZk2AAmyenZeQUAzMWl5SXVJfVKALoqbp7ecQ4QnP6BwbwAFpHYZAhWcLyMuAQzVmCIMNH4ziCNIMPU2JiJ8opkY4QTwcSYAmSRc0G7UJKvidQDggji40A4jpcQNdbmCjo8PF5glMZhwvsFhHAOBRqJttgscEQZtxAYdjnhTgApRxkNTuC5XG74BQIZSUcaIgjI2bUALfEAwMQOczLJwbLZYHYgNToJb7UkuEAAPQAggASelQxl3FkPNlPDlQmBqYiONEEfhqDTYNAAGUaHDQiys0KZ9x5kSxMRAcTgCXwnWojRaeGwMEE1FeMGashAzgAlCARiNqFBhEg0F6EZMwSirE1wtgoBKFstsKt1inMH68KBecEmmsiFYs0jHBBjtR8wFxTh69FeEHc9QvNNMMGQInqEg1BBbhkUvDngRXu9Pp2C0Xez8/ozK9Xa/MCA27HBm0vvW2OyAu2Qe5KG1AB80hyAR1hx5OQNPZ/gMouDaGxqmuuVqbpKFpWra9qOlYHAOJEYa+rOdJ4GkKR7rcB58seTaqOegrtsS14QN2eJHv2g7cq+bZjsEn7fnO/7eOo2LEaBxYECxsHwaGQjTB4wQAAqmGkAASVhQFWmEgHW5EnmeBoEVeN53n2j6Uaiw40R+Khfr4P4hmGCDJhe0xkq4MmBNS2ADn28nUHIVbStJLbkQoYYAuApJ0bprlSh8sABJOWHWbZ5qYFGnmOQ4zk8Pq3gNu5dhysC3ifn5GhwIFFCPLyoXeHATQNi0DlOegcV+YlcAeSlRw+XhBqZdliaQsIMyrE0AAiG4SgqSwrGszpwBoqabKx0A7okrXtWQTRMFJdlNkoQA="); + expect(hash.body.hash).to.eq("#wiki/4/N4IgbglgzgrghgGwgLzgFwgewHYgFwhpwBGCApiADTjTxKoY4DKZaG2A5lPqAMaYIEcAA5QyAJUwB3bngBmiMQF9qGALZlkOCgQCiaXgHoAqgBUAwlRByICNGQBOsgNqg0AT2E7CEDVYdkcvg+fqq+EnCcZC6gUEQOaMEATAAMAIwArAC0KQCcWWlJpikpeCVlKQB0JSkAWlZk2AAmyenZeQUAzMWl5SXVJfVKALoqbp7ecQ4QnP6BwbwAFpHYZAhWcLyMuAQzVmCIMNH4ziCNIMPU2JiJ8opk1BAc1wHmcGL4CgjKlONewcRMAIyJE5kFdlBJIDEtQDggji40A4jpcQNdbkijmNCBNglMZhwwcFhHAOBRqJttgscEQZtxYYdjnhTgApRxkNTuC5XG6fe6PZ6YV7vHRfH5/SZIglEggwMQOczLJwbLZYHYgNToJb7RkuEAAPQAggASblo3l3b4PEBPF5kN4fS3inH/AjYGBqYiOGUgfhqDTYNAAGUaHDQiys6L5VuoDkiZJiIDicAS+E61EaLTw7sE1EBMGashAzgAlCARiNqFBhEg0ImPK6k1LZtQmuFsFA1QtlthVusq0LbqAAuCQE01kQrA3Jo4IMdWxAAqqcMFx1BeJnpdQvNNMFmQOXqEg1BBbhkUtjpwCgeRQQuA52VxCobyB6m8MP5gRx3Y4FPcQQ8pzvSY6LmQy7qmuG7NFuIA7lg+6HiAx6nvgGSXgBaIel6DhWG2D5dgQfoBsGobhlYHBxjmKanlyeBpCkb5DiAI6rhOf6qJhQHzqBS5Ut+0TQW2LZwbOe7BEhKFnhhjbqOSoEEU+ITyZRkQwEI0weMEAAKphpAAElYUCDjwLFfmO7H/o23EgW2fGERZ66biJ8HiQQkm+Kh2bqQglZJrOTKuGZcjstgG5sb+VhyEKmrMVeAkKOpMLgIyEkqC63gaO8MABIen4hQEYXePwBbJdFDixaZ8UWYldg6vC3hIdVWWwLl2IjqF4UEHATTji01DlZVH4ZWxtXJXCRxpZxjYtTlFB+cIMyrE0AAi7aPh2Jy+j2faRnAGjVps8nQC+iSootvZkE0TAmQJkVKEAA"); }); }); }); diff --git a/src/client/components/pinboard-tile/pinboard-tile.tsx b/src/client/components/pinboard-tile/pinboard-tile.tsx index 277e82f7f..c1c3defe8 100644 --- a/src/client/components/pinboard-tile/pinboard-tile.tsx +++ b/src/client/components/pinboard-tile/pinboard-tile.tsx @@ -182,7 +182,8 @@ export class PinboardTile extends React.Component; + ignoreCase: boolean; } const defaultStringFilter: StringFilterDefinition = { @@ -98,7 +107,8 @@ const defaultStringFilter: StringFilterDefinition = { type: FilterTypes.STRING, not: false, action: StringFilterAction.CONTAINS, - values: ImmutableSet([]) + values: ImmutableSet([]), + ignoreCase: false }; export class StringFilterClause extends Record(defaultStringFilter) { @@ -186,11 +196,11 @@ export function toExpression(clause: FilterClause, { expression }: Dimension): E return not ? numExp.not() : numExp; } case FilterTypes.STRING: { - const { not, action, values } = clause as StringFilterClause; + const { not, action, values, ignoreCase } = clause as StringFilterClause; let stringExp: Expression = null; switch (action) { case StringFilterAction.CONTAINS: - stringExp = expression.contains(r(values.first())); + stringExp = expression.contains(r(values.first()), ignoreCase ? ContainsExpression.IGNORE_CASE : ContainsExpression.NORMAL); break; case StringFilterAction.IN: stringExp = expression.overlap(r(values.toArray())); diff --git a/src/common/utils/url-hash-converter/url-hash-converter.fixtures.ts b/src/common/utils/url-hash-converter/url-hash-converter.fixtures.ts index be6576ef0..51c298499 100644 --- a/src/common/utils/url-hash-converter/url-hash-converter.fixtures.ts +++ b/src/common/utils/url-hash-converter/url-hash-converter.fixtures.ts @@ -40,14 +40,15 @@ export class UrlHashConverterFixtures { } static tableHashVersion4() { - return "4/N4IgbglgzgrghgGwgLzgFwgewHYgFwhpwBGCApiADTjTxKoY4DKZaG2A5lPqAMaYIEcAA5QyAJUwB3bngBmiMQF9qGALZlkOCgQCiaXgHoAqgBUAwlRByICNGQBOs" + - "gNqg0AT2E7CEDVYdkcvg+fqq+EnCcZC6gUEQOaMEATAAMAIwArAC0KQCcWWlJpikpeCVlKQB0JSkAWlZk2AAmyenZeQUAzMWl5SXVJfVKALoqbp7ecQ4QnP6BwbwAFpHYZAh" + - "WcLyMuAQzVmCIMNH4ziCNIMPU2JiJ8opkY4QTwcSYAmSRc0G7UJKvidQDggji40A4jpcQNdbmCjo8PF5glMZhwvsFhHAOBRqJttgscEQZtxAYdjnhTgApRxkNTuC5XG74BQI" + - "ZSUcaIgjI2bUALfEAwMQOczLJwbLZYHYgNToJb7UkuEAAPQAggASelQxl3FkPNlPDlQmBqYiONEEfhqDTYNAAGUaHDQiys0KZ9x5kSxMRAcTgCXwnWojRaeGwMEE1FeMGash" + - "AzgAlCARiNqFBhEg0F6EZMwSirE1wtgoBKFstsKt1inMH68KBecEmmsiFYs0jHBBjtR8wFxTh69FeEHc9QvNNMMGQInqEg1BBbhkUvDngRXu9Pp2C0Xez8/ozK9Xa/MCA27H" + - "Bm0vvW2OyAu2Qe5KG1AB80hyAR1hx5OQNPZ/gMouDaGxqmuuVqbpKFpWra9qOlYHAOJEYa+rOdJ4GkKR7rcB58seTaqOegrtsS14QN2eJHv2g7cq+bZjsEn7fnO/7eOo2LEa" + - "BxYECxsHwaGQjTB4wQAAqmGkAASVhQFWmEgHW5EnmeBoEVeN53n2j6Uaiw40R+Khfr4P4hmGCDJhe0xkq4MmBNS2ADn28nUHIVbStJLbkQoYYAuApJ0bprlSh8sABJOWHWbZ" + - "5qYFGnmOQ4zk8Pq3gNu5dhysC3ifn5GhwIFFCPLyoXeHATQNi0DlOegcV+YlcAeSlRw+XhBqZdliaQsIMyrE0AAiG4SgqSwrGszpwBoqabKx0A7okrXtWQTRMFJdlNkoQA="; + return "4/N4IgbglgzgrghgGwgLzgFwgewHYgFwhpwBGCApiADTjTxKoY4DKZaG2A5lPqAMaYIEcAA5QyAJUwB3bngBmiMQF9qGALZlkOCgQCiaXgHoAqgBUAwlRByICNGQ" + + "BOsgNqg0AT2E7CEDVYdkcvg+fqq+EnCcZC6gUEQOaMEATAAMAIwArAC0KQCcWWlJpikpeCVlKQB0JSkAWlZk2AAmyenZeQUAzMWl5SXVJfVKALoqbp7ecQ4QnP6BwbwAF" + + "pHYZAhWcLyMuAQzVmCIMNH4ziCNIMPU2JiJ8opk1BAc1wHmcGL4CgjKlONewcRMAIyJE5kFdlBJIDEtQDggji40A4jpcQNdbkijmNCBNglMZhwwcFhHAOBRqJttgscEQZ" + + "txYYdjnhTgApRxkNTuC5XG6fe6PZ6YV7vHRfH5/SZIglEggwMQOczLJwbLZYHYgNToJb7RkuEAAPQAggASblo3l3b4PEBPF5kN4fS3inH/AjYGBqYiOGUgfhqDTYNAAGU" + + "aHDQiys6L5VuoDkiZJiIDicAS+E61EaLTw7sE1EBMGashAzgAlCARiNqFBhEg0ImPK6k1LZtQmuFsFA1QtlthVusq0LbqAAuCQE01kQrA3Jo4IMdWxAAqqcMFx1BeJnpd" + + "QvNNMFmQOXqEg1BBbhkUtjpwCgeRQQuA52VxCobyB6m8MP5gRx3Y4FPcQQ8pzvSY6LmQy7qmuG7NFuIA7lg+6HiAx6nvgGSXgBaIel6DhWG2D5dgQfoBsGobhlYHBxjmK" + + "anlyeBpCkb5DiAI6rhOf6qJhQHzqBS5Ut+0TQW2LZwbOe7BEhKFnhhjbqOSoEEU+ITyZRkQwEI0weMEAAKphpAAElYUCDjwLFfmO7H/o23EgW2fGERZ66biJ8HiQQkm+K" + + "h2bqQglZJrOTKuGZcjstgG5sb+VhyEKmrMVeAkKOpMLgIyEkqC63gaO8MABIen4hQEYXePwBbJdFDixaZ8UWYldg6vC3hIdVWWwLl2IjqF4UEHATTji01DlZVH4ZWxtXJ" + + "XCRxpZxjYtTlFB+cIMyrE0AAi7aPh2Jy+j2faRnAGjVps8nQC+iSootvZkE0TAmQJkVKEAA"; } static lineChartVersion2() { @@ -72,10 +73,10 @@ export class UrlHashConverterFixtures { static lineChartVersion4() { return "4/N4IgbglgzgrghgGwgLzgFwgewHYgFwhLYCmAtAMYAWcATmiADTjTxKoY4DKxaG2A5lHyh+NTDAAO3GhGJC8AM0RRiAXyYYAtsWQ5i+EAFE05APQBVACoBhRiAU" + "QEaYjXkBtUGgCeE/QS36TDTECgYBdgEACi5YACbuoLEwNOhYuASRAIwAInZQzhL4pJkaPn6E6HL0qgC66p5lBvkyAnbBoQRUcNgkCHZw5BzpIBC4TGCIMHL4biDEYyDYm" + - "HlgdrGB9jR25EI1TEv0ispqeyBQEkhoCSDevk1oLfxrENrYUGkGXT3EfUxQmHRhCB2gZ1k44BFGgQVDJpkxYhBgoMPgR1lByPMEa0mL4ZJhYgYQOpCC8IIdMgAGeo3KE3" + - "F4bBGvd44ML0uyibowBC0MleAyRSyZAASeQBh1AIP8bNKd1R9LeH3hiOIyJZBDg6MxoyexKQmjJ+GwXIQtT+MWmeA8wJCLnmGNBPzQEKYCgBmnQQNu5XWSi59HGk3KRJl" + - "5W0GuS+mp7Vt2HtnXE2H99jdHrwDVlIB9cD9dgmCCmhOJXoMYdgwWDEptwVj5TgsXWBJdKfFNIzWZzAfzQaLtNLEaJpwkoxIsWy8uZbxmIC+vTs2Dg2nOAw20AASpgAEa" + - "YeiD4fEWKcMUO8FEoA"; + "HlgdrGB9jR25EI1TEv0isrETBD8S8HWcCr4SggqtUxQEkhoCSDevk1oLfxrENpsFA0gYuj1iH0npg6MIQO0DOsnHAIo0CCoZNMmLEIMFBiCCOsoOR5tjWkxfDJMLEDCB1" + + "IQARBDpkAAz1D6oj4AjbYwHAnBhLl2UTdGAIWiMrwGSKWTIACTy0MOoHh/kFpS+BK5QJBWJxxDx/II12J2FJfzpSE0jPw2FFCEeIHRsne7Rc82JCIhaGRTAU0M06Fhn3K" + + "6yUovo40m5Vp6vK2muyX0bNdwWwHs64mwEfs/sDeAaGpAobg4bsEwQUxpdODBnjsGCMeVITdafKcFi62pvtzSvZheLpcjFej1Y5dcTtL2IAkoxIsWyWr5QJmIDBvTs2Dg" + + "2meAw20AASpgAEaYehTmfg2KcRWepG0oA="; } static noSlashInEncodedDefinition2() { diff --git a/src/common/view-definitions/version-4/filter-definition.fixtures.ts b/src/common/view-definitions/version-4/filter-definition.fixtures.ts index 0f4624820..4fee07c4d 100644 --- a/src/common/view-definitions/version-4/filter-definition.fixtures.ts +++ b/src/common/view-definitions/version-4/filter-definition.fixtures.ts @@ -33,13 +33,14 @@ export function booleanFilterDefinition(ref: string, values: Booleanish[], not = }; } -export function stringFilterDefinition(ref: string, action: StringFilterAction, values: string[], not = false): StringFilterClauseDefinition { +export function stringFilterDefinition(ref: string, action: StringFilterAction, values: string[], not = false, ignoreCase = false): StringFilterClauseDefinition { return { ref, type: FilterType.string, action, not, - values + values, + ignoreCase }; } diff --git a/src/common/view-definitions/version-4/filter-definition.ts b/src/common/view-definitions/version-4/filter-definition.ts index 91266f7a8..6ccef1cf9 100644 --- a/src/common/view-definitions/version-4/filter-definition.ts +++ b/src/common/view-definitions/version-4/filter-definition.ts @@ -55,6 +55,7 @@ export interface StringFilterClauseDefinition extends BaseFilterClauseDefinition type: FilterType.string; action: StringFilterAction; not: boolean; + ignoreCase: boolean; values: string[]; } @@ -103,7 +104,7 @@ const booleanFilterClauseConverter: FilterDefinitionConversion = { - toFilterClause({ action, not, values }: StringFilterClauseDefinition, dimension: Dimension): StringFilterClause { + toFilterClause({ action, not, values, ignoreCase }: StringFilterClauseDefinition, dimension: Dimension): StringFilterClause { if (action === null) { throw Error(`String filter action cannot be empty. Dimension: ${dimension}`); } @@ -119,17 +120,19 @@ const stringFilterClauseConverter: FilterDefinitionConversion