Skip to content

Commit 8883be2

Browse files
author
Anuj Rajak
committed
Fixed table component
1 parent 1ba3c4c commit 8883be2

File tree

3 files changed

+366
-257
lines changed

3 files changed

+366
-257
lines changed

src/components/TableWrapper.tsx

Lines changed: 68 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
1-
import {
2-
Chart,
3-
ChartBar,
4-
ChartAxis,
5-
ChartThemeColor,
6-
} from "@patternfly/react-charts/victory";
1+
import { Card, CardBody, CardHeader, CardTitle } from "@patternfly/react-core";
72
import {
83
Table,
94
Thead,
@@ -13,118 +8,87 @@ import {
138
Td,
149
Caption,
1510
} from "@patternfly/react-table";
16-
import { useState } from "react";
1711

18-
const TableWrapper = ({
19-
columns,
20-
rows,
21-
caption,
22-
variant,
23-
graph,
24-
selectable = false,
25-
onRowSelect,
26-
actions,
27-
setCustomData,
28-
}) => {
29-
const [selectedRows, setSelectedRows] = useState([]);
12+
interface FieldData {
13+
name: string;
14+
data_path: string;
15+
data: (string | number | boolean | null | (string | number)[])[];
16+
}
3017

31-
const toggleRow = (index) => {
32-
const newSelected = selectedRows.includes(index)
33-
? selectedRows.filter((i) => i !== index)
34-
: [...selectedRows, index];
35-
setSelectedRows(newSelected);
18+
interface TableWrapperProps {
19+
component: "table";
20+
title: string;
21+
id: string;
22+
fields: FieldData[];
23+
className?: string;
24+
}
3625

37-
onRowSelect?.(newSelected.map((i) => rows[i]));
38-
setCustomData(newSelected.map((i) => rows[i]));
39-
};
26+
const TableWrapper = (props: TableWrapperProps) => {
27+
const { title, id, fields, className } = props;
28+
// Transform fields data into table format
29+
const transformFieldsToTableData = () => {
30+
if (!fields || fields.length === 0) return { columns: [], rows: [] };
31+
32+
// Find the maximum number of data items across all fields
33+
const maxDataLength = Math.max(...fields.map((field) => field.data.length));
34+
35+
// Create columns from field names
36+
const transformedColumns = fields.map((field) => ({
37+
key: field.name,
38+
label: field.name,
39+
}));
4040

41-
const toggleAllRows = () => {
42-
const allSelected = selectedRows.length === rows.length;
43-
const newSelected = allSelected ? [] : rows.map((_, i) => i);
44-
setSelectedRows(newSelected);
41+
// Create rows based on the maximum data length
42+
const transformedRows = [];
43+
for (let i = 0; i < maxDataLength; i++) {
44+
const row: Record<string, string | number | null> = {};
45+
fields.forEach((field) => {
46+
const value = field.data[i];
47+
if (value === null || value === undefined) {
48+
row[field.name] = "N/A";
49+
} else if (Array.isArray(value)) {
50+
row[field.name] = value.join(", ");
51+
} else {
52+
row[field.name] = String(value);
53+
}
54+
});
55+
transformedRows.push(row);
56+
}
4557

46-
onRowSelect?.(newSelected.map((i) => rows[i]));
47-
setCustomData(newSelected.map((i) => rows[i]));
58+
return { columns: transformedColumns, rows: transformedRows };
4859
};
4960

50-
const graphData =
51-
graph && graph.column
52-
? rows.map((row) => ({ x: row[columns[0].key], y: row[graph.column] }))
53-
: [];
61+
const { columns, rows } = transformFieldsToTableData();
5462

5563
return (
56-
<div>
57-
<Table variant={variant} borders={variant !== "compactBorderless"}>
58-
{caption && (
64+
<Card id={id} className={className}>
65+
<CardBody>
66+
<Table variant="compact" borders>
5967
<Caption>
60-
<div
61-
style={{
62-
display: "flex",
63-
justifyContent: "space-between",
64-
alignItems: "center",
65-
}}
66-
>
67-
<span>{caption}</span>
68-
{actions}
69-
</div>
68+
<span style={{ fontWeight: "bold", fontSize: "1.1em" }}>
69+
{title}
70+
</span>
7071
</Caption>
71-
)}
72-
<Thead>
73-
<Tr>
74-
{selectable && (
75-
<Th>
76-
<input
77-
type="checkbox"
78-
aria-label="Select all rows"
79-
checked={selectedRows.length === rows.length}
80-
onChange={toggleAllRows}
81-
/>
82-
</Th>
83-
)}
84-
{columns.map((col, index) => (
85-
<Th key={index}>{col.label}</Th>
86-
))}
87-
</Tr>
88-
</Thead>
89-
<Tbody>
90-
{rows.map((row, rowIndex) => (
91-
<Tr key={rowIndex} data-testid={`row-${row.id ?? rowIndex}`}>
92-
{selectable && (
93-
<Td>
94-
<input
95-
type="checkbox"
96-
aria-label={`Select row ${rowIndex}`}
97-
checked={selectedRows.includes(rowIndex)}
98-
onChange={() => toggleRow(rowIndex)}
99-
/>
100-
</Td>
101-
)}
102-
{columns.map((col, colIndex) => (
103-
<Td key={colIndex}>{row[col.key]}</Td>
72+
<Thead>
73+
<Tr>
74+
{columns.map((col, index) => (
75+
<Th key={index}>{col.label}</Th>
10476
))}
10577
</Tr>
106-
))}
107-
</Tbody>
108-
</Table>
109-
110-
{graph && (
111-
<div style={{ height: "300px" }}>
112-
<Chart
113-
ariaTitle={graph.title || "Chart"}
114-
domainPadding={{ x: [30, 25] }}
115-
height={300}
116-
width={600}
117-
themeColor={ChartThemeColor.multiUnordered}
118-
>
119-
<ChartAxis />
120-
<ChartAxis dependentAxis />
121-
<ChartBar data={graphData} barWidth={30} />
122-
</Chart>
123-
</div>
124-
)}
125-
</div>
78+
</Thead>
79+
<Tbody>
80+
{rows.map((row, rowIndex) => (
81+
<Tr key={rowIndex} data-testid={`row-${rowIndex}`}>
82+
{columns.map((col, colIndex) => (
83+
<Td key={colIndex}>{row[col.key]}</Td>
84+
))}
85+
</Tr>
86+
))}
87+
</Tbody>
88+
</Table>
89+
</CardBody>
90+
</Card>
12691
);
12792
};
12893

12994
export default TableWrapper;
130-
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import { render, screen } from "@testing-library/react";
2+
import "@testing-library/jest-dom";
3+
4+
import DynamicComponent from "../../components/DynamicComponents";
5+
6+
describe("DynamicComponent", () => {
7+
it("should render table component with fields", () => {
8+
const tableConfig = {
9+
component: "table",
10+
title: "Test Table",
11+
id: "test-table-id",
12+
fields: [
13+
{
14+
name: "Name",
15+
data_path: "user.name",
16+
data: ["John Doe", "Jane Smith"],
17+
},
18+
{
19+
name: "Age",
20+
data_path: "user.age",
21+
data: [28, 34],
22+
},
23+
],
24+
};
25+
26+
render(<DynamicComponent config={tableConfig} />);
27+
28+
// Check that the title appears in the table caption
29+
const tableCaption = screen.getByRole("grid").querySelector("caption");
30+
expect(tableCaption).toHaveTextContent("Test Table");
31+
32+
expect(screen.getByText("Name")).toBeInTheDocument();
33+
expect(screen.getByText("Age")).toBeInTheDocument();
34+
expect(screen.getByText("John Doe")).toBeInTheDocument();
35+
expect(screen.getByText("Jane Smith")).toBeInTheDocument();
36+
expect(screen.getByText("28")).toBeInTheDocument();
37+
expect(screen.getByText("34")).toBeInTheDocument();
38+
});
39+
40+
it("should render one-card component", () => {
41+
const oneCardConfig = {
42+
component: "one-card",
43+
title: "Test Card",
44+
fields: [
45+
{
46+
name: "Field 1",
47+
data_path: "test.field1",
48+
data: ["Value 1"],
49+
},
50+
],
51+
};
52+
53+
render(<DynamicComponent config={oneCardConfig} />);
54+
55+
expect(screen.getByText("Test Card")).toBeInTheDocument();
56+
expect(screen.getByText("Field 1")).toBeInTheDocument();
57+
expect(screen.getByText("Value 1")).toBeInTheDocument();
58+
});
59+
60+
it("should handle empty config", () => {
61+
const { container } = render(<DynamicComponent config={{}} />);
62+
expect(container.firstChild).toBeNull();
63+
});
64+
65+
it("should handle null config", () => {
66+
const { container } = render(<DynamicComponent config={null} />);
67+
expect(container.firstChild).toBeNull();
68+
});
69+
70+
it("should handle unknown component", () => {
71+
const unknownConfig = {
72+
component: "unknown-component",
73+
title: "Unknown",
74+
};
75+
76+
render(<DynamicComponent config={unknownConfig} />);
77+
// Should render FragmentWrapper (empty fragment)
78+
expect(screen.queryByText("Unknown")).not.toBeInTheDocument();
79+
});
80+
});

0 commit comments

Comments
 (0)