From 54a801a5807faea1064f54af6f305df425f98c3f Mon Sep 17 00:00:00 2001 From: Aleksandr Gumroian Date: Wed, 5 Mar 2025 16:52:45 +0100 Subject: [PATCH] Add global fuzzy search and columns visibility to RichTable --- package-lock.json | 36 ++++++++ package.json | 3 +- src/bootstrap/Input.js | 16 ++-- src/common/RichTable/RichTable.js | 61 ++++++++++--- src/common/RichTable/RichTableBody.js | 56 +++++++----- .../RichTable/RichTableColumnsDropdown.js | 90 +++++++++++++++++++ src/common/RichTable/RichTableHeader.js | 6 ++ src/common/RichTable/RichTablePagination.js | 2 +- 8 files changed, 226 insertions(+), 44 deletions(-) create mode 100644 src/common/RichTable/RichTableColumnsDropdown.js diff --git a/package-lock.json b/package-lock.json index d88ca00..8b02e53 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "@fortawesome/free-regular-svg-icons": "^6.7.2", "@fortawesome/free-solid-svg-icons": "^6.7.2", "@fortawesome/react-fontawesome": "^0.2.2", + "@tanstack/match-sorter-utils": "^8.19.4", "@tanstack/react-table": "^8.21.2", "axios": "^1.7.9", "immutability-helper": "^3.1.1", @@ -3384,6 +3385,22 @@ "@sinonjs/commons": "^3.0.0" } }, + "node_modules/@tanstack/match-sorter-utils": { + "version": "8.19.4", + "resolved": "https://registry.npmjs.org/@tanstack/match-sorter-utils/-/match-sorter-utils-8.19.4.tgz", + "integrity": "sha512-Wo1iKt2b9OT7d+YGhvEPD3DXvPv2etTusIMhMUoG7fbhmxcXCtIjJDEygy91Y2JFlwGyjqiBPRozme7UD8hoqg==", + "license": "MIT", + "dependencies": { + "remove-accents": "0.5.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, "node_modules/@tanstack/react-table": { "version": "8.21.2", "resolved": "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.21.2.tgz", @@ -15865,6 +15882,12 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/remove-accents": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/remove-accents/-/remove-accents-0.5.0.tgz", + "integrity": "sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A==", + "license": "MIT" + }, "node_modules/repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", @@ -20893,6 +20916,14 @@ "@sinonjs/commons": "^3.0.0" } }, + "@tanstack/match-sorter-utils": { + "version": "8.19.4", + "resolved": "https://registry.npmjs.org/@tanstack/match-sorter-utils/-/match-sorter-utils-8.19.4.tgz", + "integrity": "sha512-Wo1iKt2b9OT7d+YGhvEPD3DXvPv2etTusIMhMUoG7fbhmxcXCtIjJDEygy91Y2JFlwGyjqiBPRozme7UD8hoqg==", + "requires": { + "remove-accents": "0.5.0" + } + }, "@tanstack/react-table": { "version": "8.21.2", "resolved": "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.21.2.tgz", @@ -30193,6 +30224,11 @@ "mdast-util-to-markdown": "^0.6.0" } }, + "remove-accents": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/remove-accents/-/remove-accents-0.5.0.tgz", + "integrity": "sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A==" + }, "repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", diff --git a/package.json b/package.json index 39bc5f0..58f705a 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "@fortawesome/free-regular-svg-icons": "^6.7.2", "@fortawesome/free-solid-svg-icons": "^6.7.2", "@fortawesome/react-fontawesome": "^0.2.2", + "@tanstack/match-sorter-utils": "^8.19.4", "@tanstack/react-table": "^8.21.2", "axios": "^1.7.9", "immutability-helper": "^3.1.1", @@ -70,4 +71,4 @@ "docs": "npx styleguidist build ", "docs:watch": "styleguidist server" } -} \ No newline at end of file +} diff --git a/src/bootstrap/Input.js b/src/bootstrap/Input.js index 9f098b0..f0b8abb 100644 --- a/src/bootstrap/Input.js +++ b/src/bootstrap/Input.js @@ -34,12 +34,14 @@ const Input = forwardRef( return (
- + {label && ( + + )}
pageSize && withPagination; return ( -
- - - -
- {paginationIsNeeded && ( - +
+ setGlobalFilter(String(e.target.value))} /> - )} + +
+
+ + + +
+ {paginationIsNeeded && ( + + )} +
); } + +function fuzzyFilter(row, columnId, value, addMeta) { + const itemRank = rankItem(row.getValue(columnId), value); + addMeta({ itemRank }); + return itemRank.passed; +} diff --git a/src/common/RichTable/RichTableBody.js b/src/common/RichTable/RichTableBody.js index 2aca395..09123e2 100644 --- a/src/common/RichTable/RichTableBody.js +++ b/src/common/RichTable/RichTableBody.js @@ -13,34 +13,44 @@ RichTableBody.propTypes = { table: propTypes.shape({ getRowModel: propTypes.func.isRequired, }).isRequired, + columns: propTypes.array.isRequired, flexRender: propTypes.func.isRequired, }; -function RichTableBody({ table, flexRender }) { +function RichTableBody({ table, columns, flexRender }) { return ( - {table.getRowModel().rows.map((row) => { - return ( - - {row.getVisibleCells().map((cell) => { - return ( - - {flexRender( - cell.column.columnDef.cell, - cell.getContext() - )} - - ); - })} - - ); - })} + {table.getRowModel().rows?.length ? ( + table.getRowModel().rows.map((row) => { + return ( + + {row.getVisibleCells().map((cell) => { + return ( + + {flexRender( + cell.column.columnDef.cell, + cell.getContext() + )} + + ); + })} + + ); + }) + ) : ( + + + {_("No results.")} + + + )} ); } diff --git a/src/common/RichTable/RichTableColumnsDropdown.js b/src/common/RichTable/RichTableColumnsDropdown.js new file mode 100644 index 0000000..e2dc643 --- /dev/null +++ b/src/common/RichTable/RichTableColumnsDropdown.js @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2019-2025 CZ.NIC z.s.p.o. (https://www.nic.cz/) + * + * This is free software, licensed under the GNU General Public License v3. + * See /LICENSE for more information. + */ + +import React from "react"; + +import { faCheck, faRotateLeft } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import PropTypes from "prop-types"; + +import Button from "../../bootstrap/Button"; + +RichTableColumnsDropdown.propTypes = { + columns: PropTypes.array.isRequired, +}; + +function RichTableColumnsDropdown({ columns }) { + return ( +
+ +
    + {columns.map((column) => { + return ( +
  • + +
  • + ); + })} + {columns.some((column) => !column.getIsVisible()) && ( + <> +
  • +
    +
  • +
  • + +
  • + + )} +
+
+ ); +} + +export default RichTableColumnsDropdown; diff --git a/src/common/RichTable/RichTableHeader.js b/src/common/RichTable/RichTableHeader.js index 4b45b9b..1325e3e 100644 --- a/src/common/RichTable/RichTableHeader.js +++ b/src/common/RichTable/RichTableHeader.js @@ -55,6 +55,12 @@ function RichTableHeader({ table, flexRender }) { ) : (