Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { render, screen, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import * as React from 'react';
import { ThemeProvider } from '@mui/material/styles';
import { MemoryRouter } from 'react-router';
import { muiTheme } from '@clients/theme/Theme/muiTheme';
import { SearchResult } from '../common/useSearchableListState';
import { Project } from '../../models/Project/types';
import { ProjectList } from './ProjectList';

const createProject = (index: number): SearchResult<Project> => ({
key: `project-${index}`,
content: `Project ${index}`,
value: {
id: `project-${index}`,
name: `Project ${index}`,
description: `Description ${index}`,
domains: [{ id: 'development', name: 'development' }],
},
});

const renderProjectList = (projects: SearchResult<Project>[]) =>
render(
<ThemeProvider theme={muiTheme}>
<MemoryRouter>
<ProjectList projects={projects} />
</MemoryRouter>
</ThemeProvider>,
);

describe('ProjectList', () => {
it('renders one page of projects at a time', async () => {
const user = userEvent.setup();
const projects = Array.from({ length: 30 }, (_, index) => createProject(index + 1));

renderProjectList(projects);

const rows = within(screen.getByRole('table', { name: /projects table/i })).getAllByRole('row');
expect(rows).toHaveLength(26);
expect(screen.getByText('Project 1')).toBeInTheDocument();
expect(screen.getByText('Project 25')).toBeInTheDocument();
expect(screen.queryByText('Project 26')).not.toBeInTheDocument();

await user.click(screen.getByLabelText(/go to next page/i));

expect(screen.getByText('Project 26')).toBeInTheDocument();
expect(screen.getByText('Project 30')).toBeInTheDocument();
expect(screen.queryByText('Project 1')).not.toBeInTheDocument();
});
});
40 changes: 37 additions & 3 deletions packages/oss-console/src/components/SelectProject/ProjectList.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import React, { forwardRef, useCallback } from 'react';
import React, { forwardRef, useCallback, useEffect, useMemo, useState } from 'react';
import Button from '@mui/material/Button';
import Table from '@mui/material/Table';
import TableHead from '@mui/material/TableHead';
import TableBody from '@mui/material/TableBody';
import TableCell from '@mui/material/TableCell';
import TablePagination from '@mui/material/TablePagination';
import TableRow from '@mui/material/TableRow';
import TableContainer from '@mui/material/TableContainer';
import Typography from '@mui/material/Typography';
Expand Down Expand Up @@ -83,8 +84,14 @@ interface ProjectListProps {
projects: SearchResult<Project>[];
}

const defaultRowsPerPage = 25;
const rowsPerPageOptions = [25, 50, 100];

/** Displays the available Projects and domains as a list of cards */
export const ProjectList: React.FC<ProjectListProps> = (props) => {
const [page, setPage] = useState(0);
const [rowsPerPage, setRowsPerPage] = useState(defaultRowsPerPage);

const selectProject = useCallback((domainId: string, projectId: string) => {
/**
* The last project/domain selected by a user is saved here and used by
Expand All @@ -99,6 +106,24 @@ export const ProjectList: React.FC<ProjectListProps> = (props) => {
setLocalStore(LOCAL_PROJECT_DOMAIN, projectDomain);
}, []);

const paginatedProjects = useMemo(() => {
const startIndex = page * rowsPerPage;
return props.projects.slice(startIndex, startIndex + rowsPerPage);
}, [page, props.projects, rowsPerPage]);

useEffect(() => {
setPage(0);
}, [props.projects]);

const onPageChange = (_event: unknown, nextPage: number) => {
setPage(nextPage);
};

const onRowsPerPageChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setRowsPerPage(Number(event.target.value));
setPage(0);
};

return (
<StyledTableContainer>
<Table aria-label="projects table">
Expand All @@ -110,7 +135,7 @@ export const ProjectList: React.FC<ProjectListProps> = (props) => {
</TableRow>
</TableHead>
<TableBody>
{props?.projects?.map?.(({ value: project, result, content }) => (
{paginatedProjects.map(({ value: project, result, content }) => (
<TableRow key={project.id}>
<TableCell scope="row">
<Typography variant="h5" className="ellipsis" data-cy="project-name">
Expand Down Expand Up @@ -143,9 +168,18 @@ export const ProjectList: React.FC<ProjectListProps> = (props) => {
</Box>
</TableCell>
</TableRow>
)) || null}
))}
</TableBody>
</Table>
<TablePagination
component="div"
count={props.projects.length}
page={page}
onPageChange={onPageChange}
rowsPerPage={rowsPerPage}
onRowsPerPageChange={onRowsPerPageChange}
rowsPerPageOptions={rowsPerPageOptions}
/>
</StyledTableContainer>
);
};
Loading