foris 6.6.1 → 6.6.2-beta.0a839bf3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -34,12 +34,14 @@ const Input = forwardRef(
34
34
 
35
35
  return (
36
36
  <div className="mb-3">
37
- <label
38
- className={`form-label ${labelClassName || ""}`.trim()}
39
- htmlFor={uid}
40
- >
41
- {label}
42
- </label>
37
+ {label && (
38
+ <label
39
+ className={`form-label ${labelClassName || ""}`.trim()}
40
+ htmlFor={uid}
41
+ >
42
+ {label}
43
+ </label>
44
+ )}
43
45
  <div className={`input-group ${groupClassName || ""}`.trim()}>
44
46
  <input
45
47
  className={`form-control ${inputClassName}`.trim()}
@@ -65,7 +67,7 @@ Input.displayName = "Input";
65
67
 
66
68
  Input.propTypes = {
67
69
  type: PropTypes.string.isRequired,
68
- label: PropTypes.string.isRequired,
70
+ label: PropTypes.string,
69
71
  helpText: PropTypes.string,
70
72
  error: PropTypes.string,
71
73
  className: PropTypes.string,
@@ -1,94 +1,118 @@
1
1
  /*
2
- * Copyright (C) 2019-2024 CZ.NIC z.s.p.o. (https://www.nic.cz/)
2
+ * Copyright (C) 2019-2025 CZ.NIC z.s.p.o. (https://www.nic.cz/)
3
3
  *
4
4
  * This is free software, licensed under the GNU General Public License v3.
5
5
  * See /LICENSE for more information.
6
6
  */
7
7
 
8
- import React, {
9
- useMemo,
10
- useState,
11
- useImperativeHandle,
12
- forwardRef,
13
- } from "react";
8
+ import React, { useMemo, useState } from "react";
14
9
 
10
+ import { rankItem } from "@tanstack/match-sorter-utils";
15
11
  import {
16
12
  flexRender,
17
13
  getCoreRowModel,
18
14
  getSortedRowModel,
15
+ getFilteredRowModel,
19
16
  getPaginationRowModel,
20
17
  useReactTable,
21
18
  } from "@tanstack/react-table";
22
19
  import PropTypes from "prop-types";
23
20
 
24
21
  import RichTableBody from "./RichTableBody";
22
+ import RichTableColumnsDropdown from "./RichTableColumnsDropdown";
25
23
  import RichTableHeader from "./RichTableHeader";
26
24
  import RichTablePagination from "./RichTablePagination";
25
+ import Input from "../../bootstrap/Input";
27
26
 
28
- const fallbackData = [];
29
-
30
- const RichTable = forwardRef(
31
- ({ columns, data, withPagination, pageSize = 5, pageIndex = 0 }, ref) => {
32
- const tableColumns = useMemo(() => columns, [columns]);
33
- const [tableData, setTableData] = useState(data ?? fallbackData);
34
- const [sorting, setSorting] = useState([]);
35
- const [pagination, setPagination] = useState({
36
- pageIndex,
37
- pageSize,
38
- });
27
+ RichTable.propTypes = {
28
+ /** Columns to be displayed in the table */
29
+ columns: PropTypes.array.isRequired,
30
+ /** Data to be displayed in the table, must be passed as a stable reference, for example, useState */
31
+ data: PropTypes.array.isRequired,
32
+ /** Whether to display pagination */
33
+ withPagination: PropTypes.bool,
34
+ /** Number of rows per page, the default is 5 */
35
+ pageSize: PropTypes.number,
36
+ /** Index of the current page */
37
+ pageIndex: PropTypes.number,
38
+ };
39
39
 
40
- useImperativeHandle(ref, () => ({
41
- setTableData,
42
- }));
40
+ export default function RichTable({
41
+ columns,
42
+ data,
43
+ withPagination,
44
+ pageSize = 5,
45
+ pageIndex = 0,
46
+ }) {
47
+ const tableColumns = useMemo(() => columns, [columns]);
48
+ const [sorting, setSorting] = useState([]);
49
+ const [pagination, setPagination] = useState({
50
+ pageIndex,
51
+ pageSize,
52
+ });
53
+ const [globalFilter, setGlobalFilter] = useState("");
54
+ const [columnVisibility, setColumnVisibility] = useState({});
43
55
 
44
- const table = useReactTable({
45
- data: tableData,
46
- columns: tableColumns,
47
- getCoreRowModel: getCoreRowModel(),
48
- getSortedRowModel: getSortedRowModel(),
49
- getPaginationRowModel: getPaginationRowModel(),
50
- onPaginationChange: setPagination,
51
- onSortingChange: setSorting,
52
- state: {
53
- sorting,
54
- pagination,
55
- },
56
- });
56
+ const table = useReactTable({
57
+ data,
58
+ columns: tableColumns,
59
+ filterFns: {
60
+ fuzzy: fuzzyFilter,
61
+ },
62
+ globalFilterFn: "fuzzy",
63
+ getCoreRowModel: getCoreRowModel(),
64
+ getSortedRowModel: getSortedRowModel(),
65
+ getPaginationRowModel: getPaginationRowModel(),
66
+ getFilteredRowModel: getFilteredRowModel(),
67
+ onSortingChange: setSorting,
68
+ onPaginationChange: setPagination,
69
+ onGlobalFilterChange: setGlobalFilter,
70
+ onColumnVisibilityChange: setColumnVisibility,
71
+ state: {
72
+ sorting,
73
+ pagination,
74
+ globalFilter,
75
+ columnVisibility,
76
+ },
77
+ });
57
78
 
58
- const paginationIsNeeded =
59
- tableData.length > pageSize && withPagination;
79
+ const paginationIsNeeded = data.length > pageSize && withPagination;
60
80
 
61
- return (
81
+ return (
82
+ <div>
83
+ <div className="d-flex justify-content-between align-items-center">
84
+ <Input
85
+ className="me-3"
86
+ type="text"
87
+ placeholder={_("Search…")}
88
+ value={globalFilter ?? ""}
89
+ onChange={(e) => setGlobalFilter(String(e.target.value))}
90
+ />
91
+ <RichTableColumnsDropdown columns={table.getAllLeafColumns()} />
92
+ </div>
62
93
  <div className="table-responsive">
63
94
  <table className="table table-hover text-nowrap">
64
95
  <RichTableHeader table={table} flexRender={flexRender} />
65
- <RichTableBody table={table} flexRender={flexRender} />
96
+ <RichTableBody
97
+ table={table}
98
+ columns={tableColumns}
99
+ flexRender={flexRender}
100
+ />
66
101
  </table>
67
102
  {paginationIsNeeded && (
68
103
  <RichTablePagination
69
104
  table={table}
70
105
  tablePageSize={pageSize}
71
- allRows={tableData.length}
106
+ allRows={data.length}
72
107
  />
73
108
  )}
74
109
  </div>
75
- );
76
- }
77
- );
78
-
79
- RichTable.propTypes = {
80
- /** Columns to be displayed in the table */
81
- columns: PropTypes.array.isRequired,
82
- /** Data to be displayed in the table */
83
- data: PropTypes.array.isRequired,
84
- /** Whether to display pagination */
85
- withPagination: PropTypes.bool,
86
- /** Number of rows per page */
87
- pageSize: PropTypes.number,
88
- /** Index of the current page */
89
- pageIndex: PropTypes.number,
90
- };
91
-
92
- RichTable.displayName = "RichTable";
110
+ </div>
111
+ );
112
+ }
93
113
 
94
- export default RichTable;
114
+ function fuzzyFilter(row, columnId, value, addMeta) {
115
+ const itemRank = rankItem(row.getValue(columnId), value);
116
+ addMeta({ itemRank });
117
+ return itemRank.passed;
118
+ }
@@ -13,34 +13,44 @@ RichTableBody.propTypes = {
13
13
  table: propTypes.shape({
14
14
  getRowModel: propTypes.func.isRequired,
15
15
  }).isRequired,
16
+ columns: propTypes.array.isRequired,
16
17
  flexRender: propTypes.func.isRequired,
17
18
  };
18
19
 
19
- function RichTableBody({ table, flexRender }) {
20
+ function RichTableBody({ table, columns, flexRender }) {
20
21
  return (
21
22
  <tbody>
22
- {table.getRowModel().rows.map((row) => {
23
- return (
24
- <tr key={row.id} className="align-middle">
25
- {row.getVisibleCells().map((cell) => {
26
- return (
27
- <td
28
- key={cell.id}
29
- {...(cell.column.columnDef.className && {
30
- className:
31
- cell.column.columnDef.className,
32
- })}
33
- >
34
- {flexRender(
35
- cell.column.columnDef.cell,
36
- cell.getContext()
37
- )}
38
- </td>
39
- );
40
- })}
41
- </tr>
42
- );
43
- })}
23
+ {table.getRowModel().rows?.length ? (
24
+ table.getRowModel().rows.map((row) => {
25
+ return (
26
+ <tr key={row.id} className="align-middle">
27
+ {row.getVisibleCells().map((cell) => {
28
+ return (
29
+ <td
30
+ key={cell.id}
31
+ {...(cell.column.columnDef
32
+ .className && {
33
+ className:
34
+ cell.column.columnDef.className,
35
+ })}
36
+ >
37
+ {flexRender(
38
+ cell.column.columnDef.cell,
39
+ cell.getContext()
40
+ )}
41
+ </td>
42
+ );
43
+ })}
44
+ </tr>
45
+ );
46
+ })
47
+ ) : (
48
+ <tr>
49
+ <td colSpan={columns.length} className="text-center py-4">
50
+ <span>{_("No results.")}</span>
51
+ </td>
52
+ </tr>
53
+ )}
44
54
  </tbody>
45
55
  );
46
56
  }
@@ -0,0 +1,90 @@
1
+ /*
2
+ * Copyright (C) 2019-2025 CZ.NIC z.s.p.o. (https://www.nic.cz/)
3
+ *
4
+ * This is free software, licensed under the GNU General Public License v3.
5
+ * See /LICENSE for more information.
6
+ */
7
+
8
+ import React from "react";
9
+
10
+ import { faCheck, faRotateLeft } from "@fortawesome/free-solid-svg-icons";
11
+ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
12
+ import PropTypes from "prop-types";
13
+
14
+ import Button from "../../bootstrap/Button";
15
+
16
+ RichTableColumnsDropdown.propTypes = {
17
+ columns: PropTypes.array.isRequired,
18
+ };
19
+
20
+ function RichTableColumnsDropdown({ columns }) {
21
+ return (
22
+ <div className="dropdown mb-3">
23
+ <Button
24
+ className="btn btn-outline-secondary dropdown-toggle"
25
+ data-bs-toggle="dropdown"
26
+ >
27
+ {_("Columns")}
28
+ </Button>
29
+ <ul className="dropdown-menu dropdown-menu-end">
30
+ {columns.map((column) => {
31
+ return (
32
+ <li key={column.id}>
33
+ <button
34
+ type="button"
35
+ className="dropdown-item d-flex align-items-center"
36
+ onClick={column.getToggleVisibilityHandler()}
37
+ style={{ paddingLeft: "2rem" }}
38
+ disabled={
39
+ column.columnDef?.enableHiding === false
40
+ }
41
+ >
42
+ {column.getIsVisible() && (
43
+ <FontAwesomeIcon
44
+ icon={faCheck}
45
+ className="position-absolute text-secondary me-2"
46
+ style={{ left: "0.6rem" }}
47
+ width="1rem"
48
+ />
49
+ )}
50
+ <span>{column.columnDef.header}</span>
51
+ </button>
52
+ </li>
53
+ );
54
+ })}
55
+ {columns.some((column) => !column.getIsVisible()) && (
56
+ <>
57
+ <li>
58
+ <hr className="dropdown-divider" />
59
+ </li>
60
+ <li>
61
+ <button
62
+ type="button"
63
+ className="dropdown-item d-flex align-items-center"
64
+ style={{ paddingLeft: "2rem" }}
65
+ onClick={() => {
66
+ // toggleVisibility for columns that are hidden
67
+ columns.forEach((column) => {
68
+ if (!column.getIsVisible()) {
69
+ column.toggleVisibility();
70
+ }
71
+ });
72
+ }}
73
+ >
74
+ <FontAwesomeIcon
75
+ icon={faRotateLeft}
76
+ className="position-absolute text-secondary me-2"
77
+ width="1rem"
78
+ style={{ left: "0.6rem" }}
79
+ />
80
+ {_("Reset")}
81
+ </button>
82
+ </li>
83
+ </>
84
+ )}
85
+ </ul>
86
+ </div>
87
+ );
88
+ }
89
+
90
+ export default RichTableColumnsDropdown;
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (C) 2019-2024 CZ.NIC z.s.p.o. (https://www.nic.cz/)
2
+ * Copyright (C) 2019-2025 CZ.NIC z.s.p.o. (https://www.nic.cz/)
3
3
  *
4
4
  * This is free software, licensed under the GNU General Public License v3.
5
5
  * See /LICENSE for more information.
@@ -32,7 +32,7 @@ function RichTableHeader({ table, flexRender }) {
32
32
  };
33
33
 
34
34
  return (
35
- <thead className="thead-light">
35
+ <thead className="table-light">
36
36
  {table.getHeaderGroups().map((headerGroup) => (
37
37
  <tr key={headerGroup.id} role="row">
38
38
  {headerGroup.headers.map((header) => (
@@ -55,6 +55,12 @@ function RichTableHeader({ table, flexRender }) {
55
55
  ) : (
56
56
  <button
57
57
  type="button"
58
+ style={
59
+ header.column.columnDef
60
+ .headerClassName === "text-center"
61
+ ? { justifySelf: "center" }
62
+ : {}
63
+ }
58
64
  className={`btn btn-link text-decoration-none text-reset fw-bold p-0 d-flex align-items-center
59
65
  ${
60
66
  header.column.getCanSort()
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (C) 2019-2024 CZ.NIC z.s.p.o. (https://www.nic.cz/)
2
+ * Copyright (C) 2019-2025 CZ.NIC z.s.p.o. (https://www.nic.cz/)
3
3
  *
4
4
  * This is free software, licensed under the GNU General Public License v3.
5
5
  * See /LICENSE for more information.
Binary file
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (C) 2019 CZ.NIC z.s.p.o. (http://www.nic.cz/)
2
+ * Copyright (C) 2019-2025 CZ.NIC z.s.p.o. (https://www.nic.cz/)
3
3
  *
4
4
  * This is free software, licensed under the GNU General Public License v3.
5
5
  * See /LICENSE for more information.
@@ -20,22 +20,25 @@ export const STATES = {
20
20
  SubmitButton.propTypes = {
21
21
  disabled: PropTypes.bool,
22
22
  state: PropTypes.oneOf(Object.keys(STATES).map((key) => STATES[key])),
23
+ label: PropTypes.string,
23
24
  };
24
25
 
25
- export function SubmitButton({ disabled, state, ...props }) {
26
+ export function SubmitButton({ disabled, state, label, ...props }) {
26
27
  const disableSubmitButton = disabled || state !== STATES.READY;
27
28
  const loadingSubmitButton = state !== STATES.READY;
28
29
 
29
- let labelSubmitButton;
30
- switch (state) {
31
- case STATES.SAVING:
32
- labelSubmitButton = _("Updating");
33
- break;
34
- case STATES.LOAD:
35
- labelSubmitButton = _("Load settings");
36
- break;
37
- default:
38
- labelSubmitButton = _("Save");
30
+ let labelSubmitButton = label;
31
+ if (!labelSubmitButton) {
32
+ switch (state) {
33
+ case STATES.SAVING:
34
+ labelSubmitButton = _("Updating");
35
+ break;
36
+ case STATES.LOAD:
37
+ labelSubmitButton = _("Load settings");
38
+ break;
39
+ default:
40
+ labelSubmitButton = _("Save");
41
+ }
39
42
  }
40
43
 
41
44
  return (
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foris",
3
- "version": "6.6.1",
3
+ "version": "6.6.2-beta.0a839bf3",
4
4
  "description": "Foris JS library is a set of components and utils for reForis application and plugins.",
5
5
  "author": "CZ.NIC, z.s.p.o.",
6
6
  "repository": {
@@ -14,17 +14,18 @@
14
14
  "license": "GPL-3.0",
15
15
  "main": "./index.js",
16
16
  "dependencies": {
17
- "@fortawesome/fontawesome-svg-core": "^6.6.0",
18
- "@fortawesome/free-regular-svg-icons": "^6.6.0",
19
- "@fortawesome/free-solid-svg-icons": "^6.6.0",
17
+ "@fortawesome/fontawesome-svg-core": "^6.7.2",
18
+ "@fortawesome/free-regular-svg-icons": "^6.7.2",
19
+ "@fortawesome/free-solid-svg-icons": "^6.7.2",
20
20
  "@fortawesome/react-fontawesome": "^0.2.2",
21
- "@tanstack/react-table": "^8.20.5",
22
- "axios": "^1.7.2",
21
+ "@tanstack/match-sorter-utils": "^8.19.4",
22
+ "@tanstack/react-table": "^8.21.2",
23
+ "axios": "^1.7.9",
23
24
  "immutability-helper": "^3.1.1",
24
25
  "moment": "^2.30.1",
25
- "qrcode.react": "^3.1.0",
26
- "react-datetime": "^3.2.0",
27
- "react-uid": "^2.3.3"
26
+ "qrcode.react": "^4.2.0",
27
+ "react-datetime": "^3.3.1",
28
+ "react-uid": "^2.4.0"
28
29
  },
29
30
  "peerDependencies": {
30
31
  "bootstrap": "^5.3.3",
@@ -34,32 +35,32 @@
34
35
  "react-router-dom": "^5.1.2"
35
36
  },
36
37
  "devDependencies": {
37
- "@babel/cli": "^7.24.7",
38
- "@babel/core": "^7.24.7",
39
- "@babel/plugin-transform-runtime": "^7.24.7",
40
- "@babel/preset-env": "^7.24.7",
41
- "@babel/preset-react": "^7.24.7",
42
- "@testing-library/react": "^8.0.9",
43
- "babel-loader": "^8.1.0",
38
+ "@babel/cli": "^7.26.4",
39
+ "@babel/core": "^7.26.9",
40
+ "@babel/plugin-transform-runtime": "^7.26.9",
41
+ "@babel/preset-env": "^7.26.9",
42
+ "@babel/preset-react": "^7.26.3",
43
+ "@testing-library/react": "^12.1.5",
44
+ "babel-loader": "^9.2.1",
44
45
  "babel-polyfill": "^6.26.0",
45
46
  "bootstrap": "^5.3.3",
46
- "css-loader": "^5.2.4",
47
+ "css-loader": "^7.1.2",
47
48
  "eslint": "^8.57.0",
48
49
  "eslint-config-reforis": "^2.1.1",
49
50
  "file-loader": "^6.0.0",
50
51
  "jest": "^29.7.0",
51
52
  "jest-environment-jsdom": "^29.7.0",
52
- "jest-mock-axios": "^4.7.3",
53
- "moment-timezone": "^0.5.45",
54
- "prettier": "^3.3.2",
53
+ "jest-mock-axios": "^4.8.0",
54
+ "moment-timezone": "^0.5.47",
55
+ "prettier": "^3.5.2",
55
56
  "prop-types": "15.8.1",
56
57
  "react": "16.9.0",
57
58
  "react-dom": "16.9.0",
58
59
  "react-router-dom": "^5.1.2",
59
60
  "react-styleguidist": "^12.0.1",
60
61
  "snapshot-diff": "^0.10.0",
61
- "style-loader": "^1.2.1",
62
- "webpack": "^5.92.1"
62
+ "style-loader": "^4.0.0",
63
+ "webpack": "^5.98.0"
63
64
  },
64
65
  "scripts": {
65
66
  "lint": "eslint src",
@@ -70,4 +71,4 @@
70
71
  "docs": "npx styleguidist build ",
71
72
  "docs:watch": "styleguidist server"
72
73
  }
73
- }
74
+ }
package/foris-6.6.1.tgz DELETED
Binary file