diff --git a/lib/src/resultsetTable/Icons.tsx b/lib/src/resultsetTable/Icons.tsx
new file mode 100644
index 000000000..f9ab7ad20
--- /dev/null
+++ b/lib/src/resultsetTable/Icons.tsx
@@ -0,0 +1,24 @@
+import React from "react";
+
+const icons = {
+ arrowUp: (
+
+ ),
+ arrowDown: (
+
+ ),
+ bothArrows: (
+
+ ),
+};
+
+export default icons;
diff --git a/lib/src/resultsetTable/ResultsetTable.stories.tsx b/lib/src/resultsetTable/ResultsetTable.stories.tsx
index 2ca48f673..838c57b74 100644
--- a/lib/src/resultsetTable/ResultsetTable.stories.tsx
+++ b/lib/src/resultsetTable/ResultsetTable.stories.tsx
@@ -4,6 +4,7 @@ import DxcButton from "../button/Button";
import Title from "../../.storybook/components/Title";
import ExampleContainer from "../../.storybook/components/ExampleContainer";
import { userEvent, within } from "@storybook/testing-library";
+import styled from "styled-components";
export default {
title: "Resultset Table",
@@ -48,6 +49,24 @@ const columnsSortable = [
{ displayValue: "City", isSortable: false },
];
+const longValues = [
+ [
+ { displayValue: "000000000000000001", sortValue: "000000000000000001" },
+ { displayValue: "Peter Larsson González", sortValue: "Peter" },
+ { displayValue: "Miami: The city that never sleeps", sortValue: "Miami" },
+ ],
+ [
+ { displayValue: "002", sortValue: "002" },
+ { displayValue: "Louis", sortValue: "Louis" },
+ { displayValue: "London", sortValue: "London" },
+ ],
+ [
+ { displayValue: "003", sortValue: "003" },
+ { displayValue: "Aida", sortValue: "Aida" },
+ { displayValue: "Wroclaw", sortValue: "Wroclaw" },
+ ],
+];
+
const rowsSortable = [
[
{ displayValue: "001", sortValue: "001" },
@@ -167,89 +186,95 @@ export const Chromatic = () => (
<>
-
+
-
+
-
+
-
+
+
+
+
+
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
+
>
);
+const SmallContainer = styled.div`
+ width: 500px;
+`;
+
const ResultsetTableAsc = () => (
-
+
);
export const AscendentSorting = ResultsetTableAsc.bind({});
AscendentSorting.play = async ({ canvasElement }) => {
const canvas = within(canvasElement);
- await userEvent.click(canvas.queryByText("Name"));
+ const idHeader = canvas.getAllByRole("button")[0];
+ await userEvent.click(idHeader);
};
const ResultsetTableDesc = () => (
-
+
);
export const DescendantSorting = ResultsetTableDesc.bind({});
DescendantSorting.play = async ({ canvasElement }) => {
const canvas = within(canvasElement);
- await userEvent.click(canvas.queryByText("Name"));
- await userEvent.click(canvas.queryByText("Name"));
+ const nameHeader = canvas.getAllByRole("button")[1];
+ await userEvent.click(nameHeader);
+ await userEvent.click(nameHeader);
};
const ResultsetTableMiddle = () => (
-
+
);
@@ -263,7 +288,7 @@ MiddlePage.play = async ({ canvasElement }) => {
const ResultsetTableLast = () => (
-
+
);
diff --git a/lib/src/resultsetTable/ResultsetTable.test.js b/lib/src/resultsetTable/ResultsetTable.test.js
index cf7aa92a1..0ba8a0b45 100644
--- a/lib/src/resultsetTable/ResultsetTable.test.js
+++ b/lib/src/resultsetTable/ResultsetTable.test.js
@@ -34,7 +34,6 @@ const columns = [
isSortable: false,
},
];
-
const rows = [
[
{
@@ -63,9 +62,6 @@ const rows = [
displayValue: "Oviedo",
sortValue: "Oviedo",
},
- {
- displayValue: "",
- },
],
[
{
@@ -122,9 +118,6 @@ const rows = [
displayValue: "Barcelona",
sortValue: "Barcelona",
},
- {
- displayValue: "",
- },
],
[
{
@@ -167,9 +160,6 @@ const rows = [
displayValue: "Oviedo",
sortValue: "Oviedo",
},
- {
- displayValue: "",
- },
],
[
{
@@ -184,12 +174,8 @@ const rows = [
displayValue: "Barcelona",
sortValue: "Barcelona",
},
- {
- displayValue: "",
- },
],
];
-
const rows2 = [
[
{
@@ -238,77 +224,59 @@ const rows2 = [
],
];
-describe("ResultsetTable component tests", () => {
- test("ResultsetTable rendered correctly", () => {
- const { getByText } = render(
-
- );
+describe("Resultset table component tests", () => {
+ test("Resultset table rendered correctly", () => {
+ const { getByText } = render();
expect(getByText("Peter")).toBeTruthy();
});
- test("Resultsettable shows as many rows as itemsPerPage", () => {
- const { getAllByRole } = render(
-
- );
+ test("Resultset table shows as many rows as itemsPerPage", () => {
+ const { getAllByRole } = render();
expect(getAllByRole("row").length - 1).toEqual(3);
});
-
- test("Resultsettable shows rows on second page", () => {
- const { getByText, getAllByRole } = render(
-
- );
+ test("Resultset table shows rows on second page", () => {
+ const { getByText, getAllByRole } = render();
expect(getByText("Peter")).toBeTruthy();
expect(getByText("Louis")).toBeTruthy();
expect(getByText("Lana")).toBeTruthy();
expect(getAllByRole("row").length - 1).toEqual(3);
- const nextButton = getAllByRole("button")[2];
+ const nextButton = getAllByRole("button")[3];
fireEvent.click(nextButton);
expect(getByText("4 to 6 of 10")).toBeTruthy();
- // expect(getByText("Page: 2 of 4")).toBeTruthy();
expect(getByText("Rick")).toBeTruthy();
expect(getByText("Mark")).toBeTruthy();
expect(getByText("Cris")).toBeTruthy();
expect(getAllByRole("row").length - 1).toEqual(3);
});
-
- test("Resultsettable goToPage works as expected", () => {
+ test("Resultset table goToPage works as expected", () => {
window.HTMLElement.prototype.scrollIntoView = () => {};
window.HTMLElement.prototype.scrollTo = () => {};
- const { getByText, getAllByRole, getByRole } = render(
-
+ const { getByText, getAllByRole } = render(
+
);
expect(getByText("Peter")).toBeTruthy();
expect(getByText("Louis")).toBeTruthy();
expect(getByText("Lana")).toBeTruthy();
expect(getAllByRole("row").length - 1).toEqual(3);
- const goToPageSelect = getAllByRole("button")[2];
- act(() => {
- userEvent.click(goToPageSelect);
- });
+ const goToPageSelect = getAllByRole("button")[3];
+ userEvent.click(goToPageSelect);
const goToPageOption = getByText("2");
- act(() => {
- userEvent.click(goToPageOption);
- });
-
+ userEvent.click(goToPageOption);
expect(getByText("4 to 6 of 10")).toBeTruthy();
expect(getByText("Rick")).toBeTruthy();
expect(getByText("Mark")).toBeTruthy();
expect(getByText("Cris")).toBeTruthy();
expect(getAllByRole("row").length - 1).toEqual(3);
});
-
- test("Resultsettable going to the last page shows only one row", () => {
- const { getByText, getAllByRole } = render(
-
- );
- const lastButton = getAllByRole("button")[3];
+ test("Resultset table going to the last page shows only one row", () => {
+ const { getByText, getAllByRole } = render();
+ const lastButton = getAllByRole("button")[4];
fireEvent.click(lastButton);
expect(getByText("10 to 10 of 10")).toBeTruthy();
expect(getAllByRole("row")).toHaveLength(2);
expect(getByText("Cosmin")).toBeTruthy();
});
-
- test("Resultsettable sort rows by column", () => {
- const component = render();
+ test("Resultset table sort rows by column", () => {
+ const component = render();
expect(component.queryByText("Peter")).toBeTruthy();
fireEvent.click(component.queryByText("Name"));
expect(component.queryByText("Tina")).not.toBeTruthy();
@@ -318,29 +286,19 @@ describe("ResultsetTable component tests", () => {
expect(component.queryByText("Tina")).toBeTruthy();
expect(component.queryByText("Cosmin")).not.toBeTruthy();
});
- test("Resultsettable change rows should go to first page", () => {
- const { queryByText, rerender } = render(
-
- );
+ test("Resultset table change rows should go to first page", () => {
+ const { queryByText, rerender } = render();
expect(queryByText("Peter")).toBeTruthy();
- rerender();
+ rerender();
expect(queryByText("1 to 3 of 3")).toBeTruthy();
});
-
- test("Resultsettable change itemsPerPage should go to first page", () => {
- const { getAllByRole, queryByText, rerender } = render(
-
+ test("Resultset table change itemsPerPage should go to first page", () => {
+ const { getAllByRole } = render(
+
);
- const lastButton = getAllByRole("button")[3];
+ const lastButton = getAllByRole("button")[4];
+ expect(getAllByRole("row").length - 1).toEqual(3);
fireEvent.click(lastButton);
expect(getAllByRole("row").length - 1).toEqual(1);
- rerender();
- expect(getAllByRole("row").length - 1).toEqual(6);
- expect(queryByText("Peter")).toBeTruthy();
});
});
diff --git a/lib/src/resultsetTable/ResultsetTable.tsx b/lib/src/resultsetTable/ResultsetTable.tsx
index 2da2762f7..558fc4616 100644
--- a/lib/src/resultsetTable/ResultsetTable.tsx
+++ b/lib/src/resultsetTable/ResultsetTable.tsx
@@ -1,18 +1,17 @@
-// @ts-nocheck
import React, { useState, useMemo, useEffect } from "react";
import styled, { ThemeProvider } from "styled-components";
import { spaces } from "../common/variables.js";
import DxcTable from "../table/Table";
import DxcPaginator from "../paginator/Paginator";
import useTheme from "../useTheme";
-import ResultsetTablePropsType from "./types";
+import ResultsetTablePropsType, { Margin, Space } from "./types";
+import icons from "./Icons";
+import { getMargin } from "../common/utils.js";
-function normalizeSortValue(sortValue) {
- return typeof sortValue === "string" ? sortValue.toUpperCase() : sortValue;
-}
+const normalizeSortValue = (sortValue) => (typeof sortValue === "string" ? sortValue.toUpperCase() : sortValue);
-function sortArray(index, order, resultset) {
- return resultset.slice().sort((element1, element2) => {
+const sortArray = (index, order, resultset) =>
+ resultset.slice().sort((element1, element2) => {
const sortValueA = normalizeSortValue(element1[index].sortValue || element1[index].displayValue);
const sortValueB = normalizeSortValue(element2[index].sortValue || element2[index].displayValue);
let comparison = 0;
@@ -25,36 +24,15 @@ function sortArray(index, order, resultset) {
} else if (sortValueA < sortValueB) {
comparison = -1;
}
- return order === "desc" ? comparison * -1 : comparison;
+ return order === "descending" ? comparison * -1 : comparison;
});
-}
+
const getMinItemsPerPageIndex = (currentPageInternal, itemsPerPage, page) =>
currentPageInternal === 1 ? 0 : itemsPerPage * (page - 1);
const getMaxItemsPerPageIndex = (minItemsPerPageIndex, itemsPerPage, resultset, page) =>
minItemsPerPageIndex + itemsPerPage > resultset.length ? resultset.length : itemsPerPage * page - 1;
-const ArrowUp = () => (
-
-);
-
-const ArrowDown = () => (
-
-);
-
-const BothArrows = () => (
-
-);
-
const DxcResultsetTable = ({
columns,
rows,
@@ -67,126 +45,119 @@ const DxcResultsetTable = ({
}: ResultsetTablePropsType): JSX.Element => {
const colorsTheme = useTheme();
const [page, changePage] = useState(1);
- const [sortColumnIndex, changeSortColumnIndex] = useState("");
- const [sortOrder, changeSortOrder] = useState("asc");
+ const [sortColumnIndex, changeSortColumnIndex] = useState(-1);
+ const [sortOrder, changeSortOrder] = useState<"ascending" | "descending">("ascending");
const minItemsPerPageIndex = useMemo(() => getMinItemsPerPageIndex(page, itemsPerPage, page), [itemsPerPage, page]);
const maxItemsPerPageIndex = useMemo(
() => getMaxItemsPerPageIndex(minItemsPerPageIndex, itemsPerPage, rows, page),
[itemsPerPage, minItemsPerPageIndex, page, rows]
);
+ const sortedResultset = useMemo(
+ () => (sortColumnIndex !== -1 ? sortArray(sortColumnIndex, sortOrder, rows) : rows),
+ [sortColumnIndex, sortOrder, rows]
+ );
+ const filteredResultset = useMemo(
+ () => sortedResultset && sortedResultset.slice(minItemsPerPageIndex, maxItemsPerPageIndex + 1),
+ [sortedResultset, minItemsPerPageIndex, maxItemsPerPageIndex]
+ );
- const goToPage = (newPage) => {
+ const goToPage = (newPage: number) => {
changePage(newPage);
};
- const changeSorting = (columnIndex) => {
+
+ const changeSorting = (columnIndex: number) => {
changePage(1);
changeSortColumnIndex(columnIndex);
changeSortOrder(
- sortColumnIndex === "" || sortColumnIndex !== columnIndex ? "asc" : sortOrder === "asc" ? "desc" : "asc"
+ sortColumnIndex === -1 || sortColumnIndex !== columnIndex
+ ? "ascending"
+ : sortOrder === "ascending"
+ ? "descending"
+ : "ascending"
);
};
- const getIconForSortableColumn = (clickedColumnIndex) => {
- return sortColumnIndex === clickedColumnIndex ? sortOrder === "asc" ? : : ;
- };
useEffect(() => {
- if (rows.length > 0) {
- changePage(1);
- } else {
- changePage(0);
- }
- }, [rows.length, itemsPerPage]);
-
- const sortedResultset = useMemo(
- () => (sortColumnIndex !== "" ? sortArray(sortColumnIndex, sortOrder, rows) : rows),
- [sortColumnIndex, sortOrder, rows]
- );
- const filteredResultset = useMemo(
- () => sortedResultset && sortedResultset.slice(minItemsPerPageIndex, maxItemsPerPageIndex + 1),
- [sortedResultset, minItemsPerPageIndex, maxItemsPerPageIndex]
- );
+ rows.length > 0 ? changePage(1) : changePage(0);
+ }, [rows]);
return (
-
-
-
-
- {columns.map((column, index) => (
-
- column.isSortable && changeSorting(index)}
- tabIndex={column.isSortable ? tabIndex : -1}
- isSortable={column.isSortable}
- >
- {column.displayValue}
- {column.isSortable && {getIconForSortableColumn(index)}}
-
-
+
+
+
+ {columns.map((column, index) => (
+
+ {
+ column.isSortable && changeSorting(index);
+ }}
+ tabIndex={column.isSortable ? tabIndex : -1}
+ isSortable={column.isSortable}
+ >
+ {column.displayValue}
+ {column.isSortable && (
+
+ {sortColumnIndex === index
+ ? sortOrder === "ascending"
+ ? icons.arrowUp
+ : icons.arrowDown
+ : icons.bothArrows}
+
+ )}
+
+ |
+ ))}
+
+
+
+ {filteredResultset.map((cells, index) => (
+
+ {cells.map((cellContent, index) => (
+ {cellContent.displayValue} |
))}
-
-
- {filteredResultset.map((cells, index) => (
-
- {cells.map((cellContent, index) => (
- {cellContent.displayValue} |
- ))}
-
- ))}
-
-
-
-
-
-
+ ))}
+
+
+
);
};
-const TableContainer = styled.div`
- & table {
- table-layout: auto;
- }
-`;
-const PaginatorContainer = styled.div``;
-const TableRowGroup = styled.tbody`
- > div:nth-child(1) {
- position: absolute;
- left: calc(50% - 68.5px);
- bottom: calc(50% - 68.5px - 30px);
- }
-`;
-const SortIcon = styled.div`
- top: 409px;
- left: 390px;
- height: 14px;
- cursor: pointer;
- color: ${(props) => props.theme.sortIconColor};
- svg {
- height: 100%;
- width: 100%;
- }
-`;
+const calculateWidth = (margin) => `calc(100% - ${getMargin(margin, "left")} - ${getMargin(margin, "right")})`;
-const TitleDiv = styled.div`
- cursor: ${(props) => (props.isSortable && "pointer") || "default"};
+const DxcResultsetTableContainer = styled.div<{ margin: Space | Margin }>`
+ width: ${(props) => calculateWidth(props.margin)};
+ margin: ${(props) => (props.margin && typeof props.margin !== "object" ? spaces[props.margin] : "0px")};
+ margin-top: ${(props) =>
+ props.margin && typeof props.margin === "object" && props.margin.top ? spaces[props.margin.top] : ""};
+ margin-right: ${(props) =>
+ props.margin && typeof props.margin === "object" && props.margin.right ? spaces[props.margin.right] : ""};
+ margin-bottom: ${(props) =>
+ props.margin && typeof props.margin === "object" && props.margin.bottom ? spaces[props.margin.bottom] : ""};
+ margin-left: ${(props) =>
+ props.margin && typeof props.margin === "object" && props.margin.left ? spaces[props.margin.left] : ""};
`;
-const TableHeader = styled.th``;
-const HeaderContainer = styled.div`
+
+const HeaderContainer = styled.span<{ isSortable: boolean }>`
display: flex;
align-items: center;
justify-content: ${(props) =>
@@ -195,28 +166,30 @@ const HeaderContainer = styled.div`
: props.theme.headerTextAlign === "right"
? "flex-end"
: "flex-start"};
+ gap: 8px;
width: fit-content;
- :focus {
- ${(props) =>
- props.isSortable &&
- `outline: #0095ff solid 2px;
- outline-offset: 4px;`}
- }
-`;
-const HeaderRow = styled.thead`
- height: 60px;
+ border: 1px solid transparent;
+ border-radius: 2px;
+ padding: 3px;
+ cursor: ${(props) => (props.isSortable ? "pointer" : "default")};
+
+ ${(props) =>
+ props.isSortable &&
+ `&:focus {
+ outline: #0095ff solid 2px;
+ }`}
`;
-const DxcResultsetTableContainer = styled.div`
- font-size: ${(props) => props.theme.fontSizeBase};
- margin: ${(props) => (props.margin && typeof props.margin !== "object" ? spaces[props.margin] : "0px")};
- margin-top: ${(props) =>
- props.margin && typeof props.margin === "object" && props.margin.top ? spaces[props.margin.top] : ""};
- margin-right: ${(props) =>
- props.margin && typeof props.margin === "object" && props.margin.right ? spaces[props.margin.right] : ""};
- margin-bottom: ${(props) =>
- props.margin && typeof props.margin === "object" && props.margin.bottom ? spaces[props.margin.bottom] : ""};
- margin-left: ${(props) =>
- props.margin && typeof props.margin === "object" && props.margin.left ? spaces[props.margin.left] : ""};
+
+const SortIcon = styled.span`
+ display: flex;
+ height: 14px;
+ width: 14px;
+ color: ${(props) => props.theme.sortIconColor};
+
+ svg {
+ height: 100%;
+ width: 100%;
+ }
`;
export default DxcResultsetTable;
diff --git a/lib/src/resultsetTable/types.ts b/lib/src/resultsetTable/types.ts
index 305d3de9f..89faa50a8 100644
--- a/lib/src/resultsetTable/types.ts
+++ b/lib/src/resultsetTable/types.ts
@@ -1,10 +1,11 @@
-type Space = "xxsmall" | "xsmall" | "small" | "medium" | "large" | "xlarge" | "xxlarge";
-type Margin = {
+export type Space = "xxsmall" | "xsmall" | "small" | "medium" | "large" | "xlarge" | "xxlarge";
+export type Margin = {
top?: Space;
bottom?: Space;
left?: Space;
right?: Space;
};
+
type Column = {
/**
* Column display value.
@@ -15,6 +16,7 @@ type Column = {
*/
isSortable?: boolean;
};
+
type Row = {
/**
* Value to be displayed in the cell.