mirror of
https://gitlab.nic.cz/turris/reforis/foris-js.git
synced 2024-11-14 17:35:35 +01:00
fixup! Add RichTable component with header, body, and pagination
This commit is contained in:
parent
fe183e0b70
commit
6d0787dc72
|
@ -37,8 +37,8 @@ const RichTable = ({
|
|||
});
|
||||
|
||||
const table = useReactTable({
|
||||
columns: tableColumns,
|
||||
data: tableData,
|
||||
columns: tableColumns,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
getSortedRowModel: getSortedRowModel(),
|
||||
getPaginationRowModel: getPaginationRowModel(),
|
||||
|
@ -57,7 +57,11 @@ const RichTable = ({
|
|||
<RichTableBody table={table} flexRender={flexRender} />
|
||||
</table>
|
||||
{withPagination && (
|
||||
<RichTablePagination table={table} tablePageSize={pageSize} />
|
||||
<RichTablePagination
|
||||
table={table}
|
||||
tablePageSize={pageSize}
|
||||
allRows={tableData.length}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -12,10 +12,16 @@ const RichTableBody = ({ table, flexRender }) => {
|
|||
<tbody>
|
||||
{table.getRowModel().rows.map((row) => {
|
||||
return (
|
||||
<tr key={row.id}>
|
||||
<tr key={row.id} className="align-middle">
|
||||
{row.getVisibleCells().map((cell) => {
|
||||
return (
|
||||
<td key={cell.id}>
|
||||
<td
|
||||
key={cell.id}
|
||||
{...(cell.column.columnDef.className && {
|
||||
className:
|
||||
cell.column.columnDef.className,
|
||||
})}
|
||||
>
|
||||
{flexRender(
|
||||
cell.column.columnDef.cell,
|
||||
cell.getContext()
|
||||
|
|
|
@ -26,44 +26,43 @@ const RichTableHeader = ({ table, flexRender }) => {
|
|||
<thead className="thead-light">
|
||||
{table.getHeaderGroups().map((headerGroup) => (
|
||||
<tr key={headerGroup.id}>
|
||||
{headerGroup.headers.map((header) => {
|
||||
return (
|
||||
<th key={header.id} colSpan={header.colSpan}>
|
||||
{header.isPlaceholder ? null : (
|
||||
<button
|
||||
className={`btn btn-link text-decoration-none text-reset fw-bold p-0 d-flex align-items-center
|
||||
{headerGroup.headers.map((header) => (
|
||||
<th key={header.id} colSpan={header.colSpan}>
|
||||
{header.isPlaceholder ||
|
||||
!header.column.columnDef.header ? null : (
|
||||
<button
|
||||
className={`btn btn-link text-decoration-none text-reset fw-bold p-0 d-flex align-items-center
|
||||
${
|
||||
header.column.getCanSort()
|
||||
? "d-flex align-items-center"
|
||||
: ""
|
||||
}
|
||||
`}
|
||||
onClick={header.column.getToggleSortingHandler()}
|
||||
title={getThTitle(header)}
|
||||
>
|
||||
{flexRender(
|
||||
header.column.columnDef.header,
|
||||
header.getContext()
|
||||
)}
|
||||
{{
|
||||
asc: (
|
||||
<FontAwesomeIcon
|
||||
icon={faSquareCaretUp}
|
||||
className="ms-1 text-primary"
|
||||
/>
|
||||
),
|
||||
desc: (
|
||||
<FontAwesomeIcon
|
||||
icon={faSquareCaretDown}
|
||||
className="ms-1 text-primary"
|
||||
/>
|
||||
),
|
||||
}[header.column.getIsSorted()] ?? null}
|
||||
</button>
|
||||
)}
|
||||
</th>
|
||||
);
|
||||
})}
|
||||
onClick={header.column.getToggleSortingHandler()}
|
||||
title={getThTitle(header)}
|
||||
>
|
||||
{flexRender(
|
||||
header.column.columnDef.header,
|
||||
header.getContext()
|
||||
)}
|
||||
{{
|
||||
asc: (
|
||||
<FontAwesomeIcon
|
||||
icon={faSquareCaretUp}
|
||||
className="ms-1 text-primary"
|
||||
/>
|
||||
),
|
||||
desc: (
|
||||
<FontAwesomeIcon
|
||||
icon={faSquareCaretDown}
|
||||
className="ms-1 text-primary"
|
||||
/>
|
||||
),
|
||||
}[header.column.getIsSorted()] ?? null}
|
||||
</button>
|
||||
)}
|
||||
</th>
|
||||
))}
|
||||
</tr>
|
||||
))}
|
||||
</thead>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* See /LICENSE for more information.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import React, { useMemo } from "react";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import {
|
||||
faAngleLeft,
|
||||
|
@ -14,89 +14,68 @@ import {
|
|||
faAnglesRight,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
|
||||
const RichTablePagination = ({ table, tablePageSize }) => {
|
||||
const RichTablePagination = ({ table, tablePageSize, allRows }) => {
|
||||
const { pagination } = table.getState();
|
||||
const prevPagBtnDisabled = !table.getCanPreviousPage();
|
||||
const nextPagBtnDisabled = !table.getCanNextPage();
|
||||
|
||||
const pageSizes = useMemo(() => {
|
||||
return [tablePageSize ?? 5, 10, 25].filter(
|
||||
(value, index, self) => self.indexOf(value) === index
|
||||
);
|
||||
}, [tablePageSize]);
|
||||
|
||||
const renderPaginationButton = (icon, ariaLabel, onClick, disabled) => (
|
||||
<li
|
||||
className={`page-item ${disabled ? "disabled" : ""}`}
|
||||
style={{ cursor: disabled ? "not-allowed" : "pointer" }}
|
||||
>
|
||||
<button
|
||||
className="page-link"
|
||||
aria-label={ariaLabel}
|
||||
onClick={onClick}
|
||||
disabled={disabled}
|
||||
>
|
||||
<FontAwesomeIcon icon={icon} />
|
||||
</button>
|
||||
</li>
|
||||
);
|
||||
|
||||
return (
|
||||
<nav
|
||||
aria-label={_("Pagination navigation bar")}
|
||||
className="d-flex gap-2 justify-content-start align-items-center mx-2 mb-1 text-nowrap"
|
||||
>
|
||||
<ul className="pagination pagination-sm mb-0">
|
||||
<li
|
||||
className={`page-item ${prevPagBtnDisabled ? "disabled" : ""}`.trim()}
|
||||
style={
|
||||
prevPagBtnDisabled
|
||||
? { cursor: "not-allowed" }
|
||||
: { cursor: "pointer" }
|
||||
}
|
||||
>
|
||||
<button
|
||||
className="page-link"
|
||||
aria-label={_("First page")}
|
||||
onClick={() => table.firstPage()}
|
||||
disabled={prevPagBtnDisabled}
|
||||
>
|
||||
<FontAwesomeIcon icon={faAnglesLeft} />
|
||||
</button>
|
||||
</li>
|
||||
<li
|
||||
className={`page-item ${prevPagBtnDisabled ? "disabled" : ""}`.trim()}
|
||||
style={
|
||||
prevPagBtnDisabled
|
||||
? { cursor: "not-allowed" }
|
||||
: { cursor: "pointer" }
|
||||
}
|
||||
>
|
||||
<button
|
||||
className="page-link"
|
||||
aria-label={_("Previous page")}
|
||||
onClick={() => table.previousPage()}
|
||||
disabled={prevPagBtnDisabled}
|
||||
>
|
||||
<FontAwesomeIcon icon={faAngleLeft} />
|
||||
</button>
|
||||
</li>
|
||||
<li
|
||||
className={`page-item ${nextPagBtnDisabled ? "disabled" : ""}`.trim()}
|
||||
style={
|
||||
nextPagBtnDisabled
|
||||
? { cursor: "not-allowed" }
|
||||
: { cursor: "pointer" }
|
||||
}
|
||||
>
|
||||
<button
|
||||
className="page-link"
|
||||
aria-label={_("Next page")}
|
||||
onClick={() => table.nextPage()}
|
||||
disabled={nextPagBtnDisabled}
|
||||
>
|
||||
<FontAwesomeIcon icon={faAngleRight} />
|
||||
</button>
|
||||
</li>
|
||||
<li
|
||||
className={`page-item ${nextPagBtnDisabled ? "disabled" : ""}`.trim()}
|
||||
style={
|
||||
nextPagBtnDisabled
|
||||
? { cursor: "not-allowed" }
|
||||
: { cursor: "pointer" }
|
||||
}
|
||||
>
|
||||
<button
|
||||
className="page-link"
|
||||
aria-label={_("Last page")}
|
||||
onClick={() => table.lastPage()}
|
||||
disabled={nextPagBtnDisabled}
|
||||
>
|
||||
<FontAwesomeIcon icon={faAnglesRight} />
|
||||
</button>
|
||||
</li>
|
||||
{renderPaginationButton(
|
||||
faAnglesLeft,
|
||||
_("First page"),
|
||||
() => table.firstPage(),
|
||||
prevPagBtnDisabled
|
||||
)}
|
||||
{renderPaginationButton(
|
||||
faAngleLeft,
|
||||
_("Previous page"),
|
||||
() => table.previousPage(),
|
||||
prevPagBtnDisabled
|
||||
)}
|
||||
{renderPaginationButton(
|
||||
faAngleRight,
|
||||
_("Next page"),
|
||||
() => table.nextPage(),
|
||||
nextPagBtnDisabled
|
||||
)}
|
||||
{renderPaginationButton(
|
||||
faAnglesRight,
|
||||
_("Last page"),
|
||||
() => table.lastPage(),
|
||||
nextPagBtnDisabled
|
||||
)}
|
||||
</ul>
|
||||
<span>
|
||||
{_("Page")}
|
||||
<span className="fw-bold">
|
||||
{table.getState().pagination.pageIndex + 1}
|
||||
{pagination.pageIndex + 1}
|
||||
{_("of")}
|
||||
{table.getPageCount().toLocaleString()}
|
||||
</span>
|
||||
|
@ -105,46 +84,23 @@ const RichTablePagination = ({ table, tablePageSize }) => {
|
|||
className="vr mx-1 align-self-center"
|
||||
style={{ height: "1.5rem" }}
|
||||
/>
|
||||
<span>
|
||||
{_("Go to page:")}
|
||||
<div className="d-inline-block ms-1 input-group input-group-sm w-auto">
|
||||
<input
|
||||
type="number"
|
||||
min="1"
|
||||
max={table.getPageCount()}
|
||||
defaultValue={table.getState().pagination.pageIndex + 1}
|
||||
onChange={(e) => {
|
||||
const page = e.target.value
|
||||
? Number(e.target.value) - 1
|
||||
: 0;
|
||||
table.setPageIndex(page);
|
||||
}}
|
||||
className="form-control w-auto"
|
||||
aria-label={_("Page number")}
|
||||
/>
|
||||
</div>
|
||||
</span>
|
||||
<span>{_("Rows per page:")}</span>
|
||||
<select
|
||||
className="form-select form-select-sm w-auto"
|
||||
aria-label={_("Select page size")}
|
||||
value={table.getState().pagination.pageSize}
|
||||
aria-label={_("Select rows per page")}
|
||||
value={pagination.pageSize}
|
||||
onChange={(e) => {
|
||||
table.setPageSize(Number(e.target.value));
|
||||
}}
|
||||
>
|
||||
{[
|
||||
// if tablePageSize is not in the list, add it
|
||||
tablePageSize === 10 ? null : tablePageSize,
|
||||
10,
|
||||
20,
|
||||
30,
|
||||
40,
|
||||
50,
|
||||
].map((pageSize) => (
|
||||
{pageSizes.map((pageSize) => (
|
||||
<option key={pageSize} value={pageSize}>
|
||||
{_("Show")} {pageSize}
|
||||
{pageSize}
|
||||
</option>
|
||||
))}
|
||||
<option key={allRows} value={allRows}>
|
||||
{_("All")}
|
||||
</option>
|
||||
</select>
|
||||
</nav>
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue
Block a user