Skip to content

Commit

Permalink
Merge branch 'main' into revise-postgresdb-and-add-middleware-connection
Browse files Browse the repository at this point in the history
  • Loading branch information
marycrawford committed Dec 12, 2024
2 parents 2085264 + a932583 commit e22c82c
Show file tree
Hide file tree
Showing 9 changed files with 284 additions and 49 deletions.
1 change: 1 addition & 0 deletions backend/dev-dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ FROM amazoncorretto:17
ENV HOME=/app
RUN mkdir -p $HOME
WORKDIR $HOME
ENTRYPOINT [ "./gradlew", "bootRun", "--continuous", "--args=--server.port=8081" ]
7 changes: 3 additions & 4 deletions backend/src/main/resources/application.yaml
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
spring:
datasource:
url: ${POSTGRES_HOST:postgres_fqdn}?sslmode=require
username: ${DB_USERNAME:postgres_user}
password: ${POSTGRES_USER:postgres_password}
name: ${POSTGRES_DB:postgres_db_name}
url: jdbc:postgresql://${POSTGRES_HOST:db}:${DB_PORT:5432}/${POSTGRES_DB:reportvision}?sslmode=${SSL_MODE:disable}
username: ${POSTGRES_USER:postgres}
password: ${POSTGRES_PASSWORD:super_secret_password}
devtools:
restart:
enabled: true
Expand Down
11 changes: 6 additions & 5 deletions dev-env.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,12 @@ services:
ports:
- "5432:5432"
environment:
POSTGRES_DB: ${postgres_db_name}
POSTGRES_HOST: ${postgres_fqdn}
POSTGRES_USER: ${postgres_user}
POSTGRES_PASSWORD: ${postgres_password}
sslmode: require
POSTGRES_DB: ${postgres_db_name:-reportvision}
POSTGRES_HOST: ${postgres_fqdn:-localhost}
POSTGRES_USER: ${postgres_user:-postgres}
POSTGRES_PASSWORD: ${postgres_password:-super_secret_password}
DB_PORT: ${postgres_port:-5432}
SSL_MODE: ${postgres_sslmode:-disable}
api:
build:
context: ./backend
Expand Down
36 changes: 16 additions & 20 deletions frontend/e2e/App.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,31 +22,27 @@ test.describe("when templates exist", async () => {
const templates = [
{
name: "MumpsQuestV1",
lab: "Quest",
createdBy: "J.Smith",
status: "Completed",
lastUpdated: new Date(Date.parse("2025-03-24T12:00:00.000-05:00")),
facility: "Quest",
condition: 'Mumps',
createdOn: new Date(Date.parse("2025-03-24T12:00:00.000-05:00")),
},
{
name: "LBTIRadar",
lab: "Radar",
createdBy: "C.Alex",
status: "Completed",
lastUpdated: new Date(Date.parse("2025-05-30T12:00:00.000-05:00")),
condition: 'Covid',
facility: "LBTI",
createdOn: new Date(Date.parse("2025-05-30T12:00:00.000-05:00")),
},
{
name: "COVIDBaylor1",
lab: "Emory",
createdBy: "A.Bryant",
status: "Completed",
lastUpdated: new Date(Date.parse("2025-06-21T12:00:00.000-05:00")),
condition: 'Covid',
facility: "Baylor",
createdOn: new Date(Date.parse("2025-06-21T12:00:00.000-05:00")),
},
{
name: "COVIDEMory",
lab: "Baylor",
createdBy: "D.Smith",
status: "Completed",
lastUpdated: new Date(Date.parse("2024-06-21T12:00:00.000-05:00")),
condition: 'Covid',
facility: "Emory",
createdOn: new Date(Date.parse("2024-06-21T12:00:00.000-05:00")),
},
];
localStorage.setItem("templates", JSON.stringify(templates));
Expand All @@ -60,14 +56,14 @@ test.describe("when templates exist", async () => {
page.getByRole("heading", { name: "Saved Templates" }),
).toBeVisible();
await expect(page.locator("tbody").getByRole("row")).toHaveCount(4);
await page.getByText("Updated On").click();
await page.getByText("Created On").click();
await expect(
page.locator("tbody").locator("tr").nth(0).getByRole("cell").nth(1),
).toHaveText("6/21/2024");
await page.getByText("Updated On").click();
).toHaveText("Mumps");
await page.getByText("Created On").click();
await expect(
page.locator("tbody").locator("tr").nth(0).getByRole("cell").nth(1),
).toHaveText("6/21/2025");
).toHaveText("Covid");
await page.close();
});
test("has links to extraction", async ({ page, baseURL }) => {
Expand Down
16 changes: 16 additions & 0 deletions frontend/src/components/TemplatesIndex/TemplatesIndex.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
.pagination-text {
color: #71767A;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: normal;
margin-left: 40px;
}

.pagination-container {
justify-content: space-between;
}

.pagination-button-group {
margin-right: 40px;
}
76 changes: 56 additions & 20 deletions frontend/src/components/TemplatesIndex/TemplatesIndex.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,24 @@ import { useNavigate } from "react-router-dom";
import extractImage from "../../assets/extract_image.svg";
import { useQuery } from "@tanstack/react-query";
import { TemplateAPI } from "../../types/templates.ts";
import usePagination from "../../hooks/use-pagination/index.ts";

import './TemplatesIndex.scss'

type TemplateIndexProps = unknown;

export const TemplatesIndex: FC<TemplateIndexProps> = () => {
const [templates, setTemplates] = useState([]);
const {
currentItems,
currentPage,
nextPage,
previousPage,
goToPage,
getPageNumbers,
hasNextPage,
hasPreviousPage
} = usePagination(templates, 10, 1);
const navigate = useNavigate();
// TODO: Pagination and sorting will be added later
const templateQuery = useQuery({
Expand Down Expand Up @@ -51,22 +64,13 @@ export const TemplatesIndex: FC<TemplateIndexProps> = () => {

const templateColumnNames = {
name: "Name",
labName: "Lab",
lab: "Lab",
createdBy: "Creator",
status: "Status",
updatedAt: "Updated On",
created: "Created On",
facility: "Facility",
condition: "Condition",
};

const templateColumnFormatters = {
updatedAt: (d) => {
const date = Date.parse(d);
if (isNaN(date)) {
return new Date().toLocaleDateString();
}
return new Date(date).toLocaleDateString();
},
lastUpdated: (d) => {
created: (d) => {
const date = Date.parse(d);
if (isNaN(date)) {
return new Date().toLocaleDateString();
Expand All @@ -77,11 +81,9 @@ export const TemplatesIndex: FC<TemplateIndexProps> = () => {

const templateColumns = [
"name",
"updatedAt",
"createdBy",
"lab",
"status",
"labName",
"condition",
"facility",
"created",
];

useEffect(() => {
Expand Down Expand Up @@ -148,7 +150,7 @@ export const TemplatesIndex: FC<TemplateIndexProps> = () => {
</>
);
}

return (
<>
<div className="bg-white padding-2 border-gray-5 border-1px">
Expand Down Expand Up @@ -181,10 +183,44 @@ export const TemplatesIndex: FC<TemplateIndexProps> = () => {
<h2>Saved Templates</h2>
<SortableTable
columns={templateColumns}
data={templates}
data={currentItems}
formatters={templateColumnFormatters}
columnNames={templateColumnNames}
/>
<div className="display-flex flex-row width-full pagination-container">
<p className="pagination-text">
Showing {Math.min(currentPage * 10, templates.length)} of {templates.length} templates
</p>
<div className="flex items-center justify-center space-x-2 pagination-button-group">
<Button
onClick={previousPage}
disabled={!hasPreviousPage}
type="button"
>
Previous
</Button>

{getPageNumbers().map(pageNum => (
<Button
key={pageNum}
onClick={() => goToPage(pageNum)}
type="button"
outline={pageNum !== currentPage}
>
{pageNum}
</Button>
))}

<Button
onClick={nextPage}
disabled={!hasNextPage}
type="button"
>
Next
</Button>
</div>
</div>

</div>
</div>
</>
Expand Down
87 changes: 87 additions & 0 deletions frontend/src/hooks/use-pagination/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { useState, useMemo } from "react";


const usePagination = <T>(items: T[] = [], itemsPerPage = 10, initialPage = 1) => {
const [currentPage, setCurrentPage] = useState(initialPage);

// Calculate total number of pages
const totalPages = useMemo(() =>
Math.ceil(items.length / itemsPerPage),
[items.length, itemsPerPage]
);

// Ensure current page stays within bounds
useMemo(() => {
if (currentPage > totalPages) {
setCurrentPage(totalPages || 1);
}
}, [currentPage, totalPages]);

// Get current page items
const currentItems = useMemo(() => {
const startIndex = (currentPage - 1) * itemsPerPage;
const endIndex = startIndex + itemsPerPage;
return items.slice(startIndex, endIndex);
}, [items, currentPage, itemsPerPage]);

// Navigation functions
const goToPage = (pageNumber: number) => {
const page = Math.max(1, Math.min(pageNumber, totalPages));
setCurrentPage(page);
};

const nextPage = () => {
if (currentPage < totalPages) {
setCurrentPage(prev => prev + 1);
}
};

const previousPage = () => {
if (currentPage > 1) {
setCurrentPage(prev => prev - 1);
}
};

const firstPage = () => {
setCurrentPage(1);
};

const lastPage = () => {
setCurrentPage(totalPages);
};

// Generate page numbers for pagination display
const getPageNumbers = (maxVisible = 5) => {
const pages = [];
let startPage = Math.max(1, currentPage - Math.floor(maxVisible / 2));
const endPage = Math.min(totalPages, startPage + maxVisible - 1);

// Adjust start page if end page is maxed out
if (endPage - startPage + 1 < maxVisible) {
startPage = Math.max(1, endPage - maxVisible + 1);
}

for (let i = startPage; i <= endPage; i++) {
pages.push(i);
}

return pages;
};

return {
currentPage,
currentItems,
totalPages,
itemsPerPage,
goToPage,
nextPage,
previousPage,
firstPage,
lastPage,
getPageNumbers,
hasNextPage: currentPage < totalPages,
hasPreviousPage: currentPage > 1
};
};

export default usePagination;
Loading

0 comments on commit e22c82c

Please sign in to comment.