diff --git a/source/console/src/Components/Dashboard/Dashboard.js b/source/console/src/Components/Dashboard/Dashboard.js index 7009fdb..e8696a6 100644 --- a/source/console/src/Components/Dashboard/Dashboard.js +++ b/source/console/src/Components/Dashboard/Dashboard.js @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import React from "react"; -import { Table, Spinner } from "reactstrap"; +import { Table, Spinner, Input, Pagination, PaginationItem, PaginationLink } from "reactstrap"; import { Link } from "react-router-dom"; import { get } from "aws-amplify/api"; @@ -14,13 +14,19 @@ class Dashboard extends React.Component { super(props); this.state = { Items: [], + filteredItems: [], isLoading: true, + searchQuery: '', + currentPage: 1, + itemsPerPage: 10, + totalTests: 0, }; } getItems = async () => { this.setState({ Items: [], + filteredItems: [], isLoading: true, }); @@ -38,19 +44,135 @@ class Dashboard extends React.Component { this.setState({ Items: data.Items, + filteredItems: data.Items, isLoading: false, + totalTests: data.Items.length, }); } catch (err) { - alert(err); + alert(err); } }; + filterItems = (items, query) => { + if (!query) return items; + + const normalizedQuery = query.toLowerCase(); + + return items.filter(item => + Object.values(item).some(value => + value && value.toString().toLowerCase().includes(normalizedQuery) + ) + ); + }; + + handleSearchChange = (event) => { + const searchQuery = event.target.value; + this.setState({ searchQuery, currentPage: 1 }, this.updateFilteredItems); + }; + + updateFilteredItems = () => { + const { Items, searchQuery } = this.state; + const filteredItems = this.filterItems(Items, searchQuery); + this.setState({ filteredItems }); + }; + + + handlePageChange = (pageNumber) => { + this.setState({ currentPage: pageNumber }); + }; + + calculatePaginationIndices = (currentPage, itemsPerPage, totalItems) => { + const indexOfLastItem = currentPage * itemsPerPage; + const indexOfFirstItem = indexOfLastItem - itemsPerPage; + const currentItems = totalItems.slice(indexOfFirstItem, indexOfLastItem); + const currentLoadRangeStart = indexOfFirstItem + 1; + const currentLoadRangeEnd = Math.min(indexOfLastItem, totalItems.length); + + return { currentItems, currentLoadRangeStart, currentLoadRangeEnd }; + }; + + componentDidMount() { this.getItems(); } + renderTableBody = (items) => { + const { currentPage, itemsPerPage } = this.state; + const { currentItems } = this.calculatePaginationIndices(currentPage, itemsPerPage, items); + + return ( + + {currentItems.map((item) => { + return ( + + {item.testName} + {item.testId} + {item.testDescription} + {item.startTime ? item.startTime : ""} + {item.status} + {item.nextRun} + {item.scheduleRecurrence} + + + + + + + ); + })} + + ); + }; + + renderPagination = (items) => { + const { currentPage, itemsPerPage } = this.state; + const totalPages = Math.ceil(items.length / itemsPerPage); + + if (totalPages <= 1) return null; + + const pageNumbers = []; + for (let i = 1; i <= totalPages; i++) { + pageNumbers.push(i); + } + + const previousPageItem = ( + + this.handlePageChange(currentPage - 1)}> + Previous page + + + ); + + const nextPageItem = ( + = totalPages}> + this.handlePageChange(currentPage + 1)}> + Next page + + + ); + + return ( + + {previousPageItem} + {pageNumbers.map((number) => ( + + this.handlePageChange(number)}> + {number} + + + ))} + {nextPageItem} + + ); + }; + render() { - const { Items } = this.state; + const { filteredItems, isLoading, searchQuery, currentPage, itemsPerPage } = this.state; + const { currentLoadRangeStart, currentLoadRangeEnd } = this.calculatePaginationIndices(currentPage, itemsPerPage, filteredItems); + const loadTests = filteredItems; const welcome = (
@@ -58,30 +180,6 @@ class Dashboard extends React.Component {
); - const tableBody = ( - - {Items.map((item) => ( - - {item.testName} - {item.testId} - {item.testDescription} - {item.startTime} - {item.status} - {item.nextRun} - {item.scheduleRecurrence} - - - - - - - ))} - - ); - return (
} />
- - - - - - - - - - - - - - {tableBody} -
NameIdDescriptionLast Run (UTC)StatusNext Run (UTC)RecurrenceDetails
- {this.state.isLoading && ( + + + + + + + + + + + + + + + {this.renderTableBody(loadTests)} +
NameIdDescriptionLast Run (UTC)StatusNext Run (UTC)RecurrenceDetails
+
+ {filteredItems.length === 0 ? ( +
+ The search didn't find anything +
+ ) : ( +
+ Showing rows {currentLoadRangeStart} to {currentLoadRangeEnd} of {loadTests.length} +
+ )} + {this.renderPagination(loadTests)} +
+ {isLoading && (
)}
- {!this.state.isLoading && Items.length === 0 && welcome} + {!isLoading && ( + (this.state.totalTests === 0 && welcome) + )}
); - } +} } export default Dashboard; diff --git a/source/console/src/index.css b/source/console/src/index.css index 96f2705..838e620 100644 --- a/source/console/src/index.css +++ b/source/console/src/index.css @@ -555,3 +555,34 @@ img { font-weight: 600; } } + +.pagination .disabled { + display: none; +} +.page-item .page-link{ + color: black !important; + box-shadow: none; +} +.page-item.active .page-link{ + color: white !important; + background-color: #ffa500; + border-color: #ffa500; +} +.page-container { + display: flex; + justify-content: space-between; + align-items: center; + height: 100%; +} +.page-container.no-results { + justify-content: center; +} +.rows-info, .pagination { + flex: 1; +} +.search-info { + display: flex; + justify-content: center; + align-items: center; + text-align: center; +}