Skip to content

Commit

Permalink
Merge pull request #156 from IQSS/feature/149-react-table-manual-pagi…
Browse files Browse the repository at this point in the history
…nation-setup

149 - Configure manual pagination in the Files Table UI
  • Loading branch information
kcondon authored Sep 15, 2023
2 parents 0ad3728 + f026545 commit 2f5126a
Show file tree
Hide file tree
Showing 29 changed files with 993 additions and 534 deletions.
52 changes: 52 additions & 0 deletions src/files/domain/models/FilePaginationInfo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
export class FilePaginationInfo {
constructor(
public readonly page: number = 1,
public readonly pageSize: number = 10,
public readonly totalFiles: number = 0
) {}

withTotal(total: number): FilePaginationInfo {
return new FilePaginationInfo(this.page, this.pageSize, total)
}
goToPage(page: number): FilePaginationInfo {
return new FilePaginationInfo(page, this.pageSize, this.totalFiles)
}

goToPreviousPage(): FilePaginationInfo {
if (!this.previousPage) throw new Error('No previous page')
return this.goToPage(this.previousPage)
}

goToNextPage(): FilePaginationInfo {
if (!this.nextPage) throw new Error('No next page')
return this.goToPage(this.nextPage)
}

withPageSize(pageSize: number): FilePaginationInfo {
const getNewPage = (oldPageSize: number, newPageSize: number) => {
const newPage = Math.ceil((this.page * oldPageSize) / newPageSize)
return newPage > 0 ? newPage : 1
}
return new FilePaginationInfo(getNewPage(this.pageSize, pageSize), pageSize, this.totalFiles)
}

get totalPages(): number {
return Math.ceil(this.totalFiles / this.pageSize)
}

get hasPreviousPage(): boolean {
return this.page > 1
}

get hasNextPage(): boolean {
return this.page < this.totalPages
}

get previousPage(): number | undefined {
return this.hasPreviousPage ? this.page - 1 : undefined
}

get nextPage(): number | undefined {
return this.hasNextPage ? this.page + 1 : undefined
}
}
2 changes: 2 additions & 0 deletions src/files/domain/repositories/FileRepository.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { File } from '../models/File'
import { FileCriteria } from '../models/FileCriteria'
import { FilesCountInfo } from '../models/FilesCountInfo'
import { FilePaginationInfo } from '../models/FilePaginationInfo'

export interface FileRepository {
getAllByDatasetPersistentId: (
datasetPersistentId: string,
version?: string,
paginationInfo?: FilePaginationInfo,
criteria?: FileCriteria
) => Promise<File[]>
getCountInfoByDatasetPersistentId: (
Expand Down
4 changes: 3 additions & 1 deletion src/files/domain/useCases/getFilesByDatasetPersistentId.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { FileRepository } from '../repositories/FileRepository'
import { File, FileVersionNotNumber } from '../models/File'
import { FileCriteria } from '../models/FileCriteria'
import { FilePaginationInfo } from '../models/FilePaginationInfo'

export async function getFilesByDatasetPersistentId(
fileRepository: FileRepository,
persistentId: string,
version: string = FileVersionNotNumber.LATEST,
paginationInfo?: FilePaginationInfo,
criteria?: FileCriteria
): Promise<File[]> {
return fileRepository
.getAllByDatasetPersistentId(persistentId, version, criteria)
.getAllByDatasetPersistentId(persistentId, version, paginationInfo, criteria)
.catch((error: Error) => {
throw new Error(error.message)
})
Expand Down
11 changes: 9 additions & 2 deletions src/files/infrastructure/FileJSDataverseRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,17 @@ import { File } from '../domain/models/File'
import { FilesMockData } from '../../stories/files/FileMockData'
import { FilesCountInfo } from '../domain/models/FilesCountInfo'
import { FilesCountInfoMother } from '../../../tests/component/files/domain/models/FilesCountInfoMother'
import { FilePaginationInfo } from '../domain/models/FilePaginationInfo'

export class FileJSDataverseRepository implements FileRepository {
// eslint-disable-next-line unused-imports/no-unused-vars
getAllByDatasetPersistentId(persistentId: string, version?: string): Promise<File[]> {
getAllByDatasetPersistentId(
// eslint-disable-next-line unused-imports/no-unused-vars
persistentId: string,
// eslint-disable-next-line unused-imports/no-unused-vars
version?: string,
// eslint-disable-next-line unused-imports/no-unused-vars
paginationInfo?: FilePaginationInfo
): Promise<File[]> {
// TODO - implement using js-dataverse
return new Promise((resolve) => {
setTimeout(() => {
Expand Down
17 changes: 12 additions & 5 deletions src/sections/dataset/dataset-files/DatasetFiles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { FilesTable } from './files-table/FilesTable'
import { FileCriteriaForm } from './file-criteria-form/FileCriteriaForm'
import { FileCriteria } from '../../../files/domain/models/FileCriteria'
import { useFiles } from './useFiles'
import { FilePaginationInfo } from '../../../files/domain/models/FilePaginationInfo'
import { FilesPagination } from './files-pagination/FilesPagination'

interface DatasetFilesProps {
filesRepository: FileRepository
Expand All @@ -16,25 +18,30 @@ export function DatasetFiles({
datasetPersistentId,
datasetVersion
}: DatasetFilesProps) {
const [paginationInfo, setPaginationInfo] = useState<FilePaginationInfo>(new FilePaginationInfo())
const [criteria, setCriteria] = useState<FileCriteria>(new FileCriteria())
const { files, isLoading, filesCountInfo } = useFiles(
filesRepository,
datasetPersistentId,
datasetVersion,
paginationInfo,
criteria
)
const handleCriteriaChange = (newCriteria: FileCriteria) => {
setCriteria(newCriteria)
}

return (
<>
<FileCriteriaForm
criteria={criteria}
onCriteriaChange={handleCriteriaChange}
onCriteriaChange={setCriteria}
filesCountInfo={filesCountInfo}
/>
<FilesTable files={files} isLoading={isLoading} filesCountTotal={filesCountInfo.total} />
<FilesTable files={files} isLoading={isLoading} paginationInfo={paginationInfo} />
<FilesPagination
page={paginationInfo.page}
pageSize={paginationInfo.pageSize}
total={filesCountInfo.total}
onPaginationInfoChange={setPaginationInfo}
/>
</>
)
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
.row {
justify-content: center;
}

.container {
display: flex;
align-items: center;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { Col, Pagination, Row } from '@iqss/dataverse-design-system'
import { PageNumbersButtonsWithEllipsis } from './PageNumbersButtonsWithEllipsis'
import { PageSizeSelector } from './PageSizeSelector'
import styles from './FilesPagination.module.scss'
import { FilePaginationInfo } from '../../../../files/domain/models/FilePaginationInfo'
import { useEffect, useState } from 'react'

interface FilesPaginationProps {
onPaginationInfoChange: (paginationInfo: FilePaginationInfo) => void
page: number
pageSize: number
total: number
}
const NO_PAGES = 0
export function FilesPagination({
onPaginationInfoChange,
page,
pageSize,
total
}: FilesPaginationProps) {
const [paginationInfo, setPaginationInfo] = useState<FilePaginationInfo>(
new FilePaginationInfo(page, pageSize, total)
)
const goToPage = (newPage: number) => {
setPaginationInfo(paginationInfo.goToPage(newPage))
}
const goToPreviousPage = () => {
setPaginationInfo(paginationInfo.goToPreviousPage())
}
const goToNextPage = () => {
setPaginationInfo(paginationInfo.goToNextPage())
}
const setPageSize = (newPageSize: number) => {
setPaginationInfo(paginationInfo.withPageSize(newPageSize))
}

useEffect(() => {
onPaginationInfoChange(paginationInfo)
}, [paginationInfo])

useEffect(() => {
setPaginationInfo(paginationInfo.withTotal(total))
}, [total])

if (paginationInfo.totalPages === NO_PAGES) {
return <></>
}
return (
<Row className={styles.row}>
<Col md="auto">
<div className={styles.container}>
<Pagination>
<Pagination.First
onClick={() => goToPage(1)}
disabled={!paginationInfo.hasPreviousPage}
/>
<Pagination.Prev
onClick={() => goToPreviousPage()}
disabled={!paginationInfo.hasPreviousPage}
/>
<PageNumbersButtonsWithEllipsis
selectedPageIndex={paginationInfo.page - 1}
pageCount={paginationInfo.totalPages}
goToPage={goToPage}
/>
<Pagination.Next
onClick={() => goToNextPage()}
disabled={!paginationInfo.hasNextPage}
/>
<Pagination.Last
onClick={() => goToPage(paginationInfo.totalPages)}
disabled={!paginationInfo.hasNextPage}
/>
</Pagination>
<PageSizeSelector pageSize={paginationInfo.pageSize} setPageSize={setPageSize} />
</div>
</Col>
</Row>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export function PageNumbersButtons({
<Pagination.Item
key={pageNumber}
pageNumber={pageNumber}
onClick={() => goToPage(pageIndex)}
onClick={() => goToPage(pageIndex + 1)}
active={selectedPageIndex === pageIndex}
/>
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Pagination } from '@iqss/dataverse-design-system'
import { PageNumbersButtons } from './PageNumbersButtons'

interface TablePaginationNumbersWithEllipsisProps {
interface PageNumbersButtonsWithEllipsisProps {
selectedPageIndex: number
pageCount: number
goToPage: (pageIndex: number) => void
Expand All @@ -11,7 +11,7 @@ export function PageNumbersButtonsWithEllipsis({
selectedPageIndex,
pageCount,
goToPage
}: TablePaginationNumbersWithEllipsisProps) {
}: PageNumbersButtonsWithEllipsisProps) {
const firstPageNumber = 1
const firstPageIndex = 0
const lastPageIndex = pageCount - 1
Expand All @@ -28,7 +28,7 @@ export function PageNumbersButtonsWithEllipsis({
<Pagination.Item
pageNumber={firstPageNumber}
active={selectedPageIndex === firstPageIndex}
onClick={() => goToPage(firstPageIndex)}
onClick={() => goToPage(firstPageIndex + 1)}
/>
<Pagination.Ellipsis />
</>
Expand All @@ -45,7 +45,7 @@ export function PageNumbersButtonsWithEllipsis({
<Pagination.Item
pageNumber={pageCount}
active={selectedPageIndex === lastPageIndex}
onClick={() => goToPage(lastPageIndex)}
onClick={() => goToPage(lastPageIndex + 1)}
/>
</>
)}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import styles from './TablePagination.module.scss'
import styles from './FilesPagination.module.scss'
import { useTranslation } from 'react-i18next'

export function PageSizeSelector({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
.pagination-container {
justify-content: center;
}

.file-info-header {
display: flex;
align-items: flex-start;
Expand Down
44 changes: 15 additions & 29 deletions src/sections/dataset/dataset-files/files-table/FilesTable.tsx
Original file line number Diff line number Diff line change
@@ -1,55 +1,41 @@
import { Col, Row, Table } from '@iqss/dataverse-design-system'
import { Table } from '@iqss/dataverse-design-system'
import { FilesTableHeader } from './FilesTableHeader'
import { FilesTableBody } from './FilesTableBody'
import { TablePagination } from './table-pagination/TablePagination'
import styles from './FilesTable.module.scss'
import { useFilesTable } from './useFilesTable'
import { File } from '../../../../files/domain/models/File'
import { RowSelectionMessage } from './row-selection/RowSelectionMessage'
import { ZipDownloadLimitMessage } from './zip-download-limit-message/ZipDownloadLimitMessage'
import { SpinnerSymbol } from './spinner-symbol/SpinnerSymbol'
import { FilePaginationInfo } from '../../../../files/domain/models/FilePaginationInfo'

interface FilesTableProps {
files: File[]
isLoading: boolean
filesCountTotal: number
paginationInfo: FilePaginationInfo
}

export function FilesTable({ files, isLoading, filesCountTotal }: FilesTableProps) {
const { table, rowSelection, setRowSelection } = useFilesTable(files)
export function FilesTable({ files, isLoading, paginationInfo }: FilesTableProps) {
const { table, fileSelection, selectAllFiles, clearFileSelection } = useFilesTable(
files,
paginationInfo
)

if (isLoading) {
return <SpinnerSymbol />
}
return (
<div>
<>
<RowSelectionMessage
selectedFilesCount={Object.keys(rowSelection).length}
totalFilesCount={filesCountTotal}
setRowSelection={setRowSelection}
/>
<ZipDownloadLimitMessage
selectedFiles={table.getSelectedRowModel().flatRows.map((row) => row.original)}
fileSelection={fileSelection}
selectAllRows={selectAllFiles}
totalFilesCount={paginationInfo.totalFiles}
clearRowSelection={clearFileSelection}
/>
<ZipDownloadLimitMessage fileSelection={fileSelection} />
<Table>
<FilesTableHeader headers={table.getHeaderGroups()} />
<FilesTableBody rows={table.getRowModel().rows} />
</Table>
<Row className={styles['pagination-container']}>
<Col md="auto">
<TablePagination
pageIndex={table.getState().pagination.pageIndex}
pageCount={table.getPageCount()}
pageSize={table.getState().pagination.pageSize}
setPageSize={table.setPageSize}
goToPage={table.setPageIndex}
goToPreviousPage={table.previousPage}
goToNextPage={table.nextPage}
canGoToPreviousPage={table.getCanPreviousPage()}
canGoToNextPage={table.getCanNextPage()}
/>
</Col>
</Row>
</div>
</>
)
}
Loading

0 comments on commit 2f5126a

Please sign in to comment.