Skip to content

Commit

Permalink
Merge pull request #415 from IQSS/feature/405-files-tab-content-infin…
Browse files Browse the repository at this point in the history
…ite-scrolling

405 Infinite Scrolling on Dataset Files
  • Loading branch information
GPortas authored Jun 24, 2024
2 parents fa7497a + 821e5e7 commit 107aaca
Show file tree
Hide file tree
Showing 56 changed files with 2,325 additions and 142 deletions.
6 changes: 6 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@
"attributes": false
}
}
],
"react-hooks/exhaustive-deps": [
"warn",
{
"additionalHooks": "(useDeepCompareEffect|useDeepCompareCallback|useDeepCompareMemo)"
}
]
},
"overrides": [
Expand Down
12 changes: 12 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"react-topbar-progress-indicator": "4.1.1",
"sass": "1.58.1",
"typescript": "4.9.5",
"use-deep-compare": "1.2.1",
"vite-plugin-istanbul": "4.0.1",
"web-vitals": "2.1.4"
},
Expand Down
1 change: 1 addition & 0 deletions packages/design-system/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
- **FormLabel:** extend Props Interface to accept `htmlFor` prop.
- **SelectMultiple:** NEW multiple selector for occasions when you can choose more than one option.
- **FormSelectMultiple:** The new multiple selector is added to the "FormGroup" components.
- **DropdownButton:** extend Props Interface to accept `ariaLabel` prop.
- **DropdownButtonItem:** extend Props Interface to accept `as` prop.
- **Accordion:** ability to forward react ref.
- **DynamicFieldsButtons:** Removed from design system.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ interface DropdownButtonProps {
onSelect?: (eventKey: string | null) => void
disabled?: boolean
children: ReactNode
ariaLabel?: string
}

export function DropdownButton({
Expand All @@ -28,6 +29,7 @@ export function DropdownButton({
asButtonGroup,
onSelect,
disabled,
ariaLabel,
children
}: DropdownButtonProps) {
return (
Expand All @@ -40,6 +42,7 @@ export function DropdownButton({
{title}
</>
}
aria-label={ariaLabel || title}
variant={variant}
as={asButtonGroup ? ButtonGroup : undefined}
disabled={disabled}
Expand Down
3 changes: 3 additions & 0 deletions public/locales/en/files.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
{
"filesLoading": "Files loading spinner symbol",
"errorUnkownGetFilesFromDataset": "There was an error getting the files total download size",
"errorUnkownGetFilesCountInfo": "There was an error getting the files count info",
"errorUnkownGetFilesTotalDownloadSize": "There was an error getting the files total download size",
"table": {
"rowSelection": {
"filesSelected_one": "{{count}} file is currently selected.",
Expand Down
2 changes: 1 addition & 1 deletion public/locales/en/pagination.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"accumulated": {
"one": "{{formattedCount}} {{item}}",
"lessThanPageSize": "{{formattedCount}} {{item}}s",
"moreThanPageSize": "{{accumulated}} of {{formattedCount}} {{item}}s seen"
"moreThanPageSize": "{{accumulated}} of {{formattedCount}} {{item}}s displayed"
},
"pageSize": "{{item}}s per page"
}
6 changes: 6 additions & 0 deletions src/files/domain/models/FilesWithCount.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { FilePreview } from './FilePreview'

export interface FilesWithCount {
files: FilePreview[]
totalFilesCount: number
}
7 changes: 7 additions & 0 deletions src/files/domain/repositories/FileRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { FilesCountInfo } from '../models/FilesCountInfo'
import { DatasetVersion, DatasetVersionNumber } from '../../../dataset/domain/models/Dataset'
import { FilePaginationInfo } from '../models/FilePaginationInfo'
import { FilePreview } from '../models/FilePreview'
import { FilesWithCount } from '../models/FilesWithCount'
import { FileHolder } from './File'

export interface FileRepository {
Expand All @@ -27,6 +28,12 @@ export interface FileRepository {
getById: (id: number, datasetVersionNumber?: string) => Promise<File | undefined>
getMultipleFileDownloadUrl: (ids: number[], downloadMode: FileDownloadMode) => string
getFileDownloadUrl: (id: number, downloadMode: FileDownloadMode) => string
getAllByDatasetPersistentIdWithCount: (
datasetPersistentId: string,
datasetVersion: DatasetVersion,
paginationInfo?: FilePaginationInfo,
criteria?: FileCriteria
) => Promise<FilesWithCount>
uploadFile: (
datasetId: number | string,
file: FileHolder,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { FileRepository } from '../repositories/FileRepository'
import { FileCriteria } from '../models/FileCriteria'
import { DatasetVersion } from '../../../dataset/domain/models/Dataset'
import { FilePaginationInfo } from '../models/FilePaginationInfo'
import { FilesWithCount } from '../models/FilesWithCount'

export async function getFilesByDatasetPersistentIdWithCount(
fileRepository: FileRepository,
datasetPersistentId: string,
datasetVersion: DatasetVersion,
paginationInfo?: FilePaginationInfo,
criteria?: FileCriteria
): Promise<FilesWithCount> {
return fileRepository
.getAllByDatasetPersistentIdWithCount(
datasetPersistentId,
datasetVersion,
paginationInfo,
criteria
)
.catch((error: Error) => {
throw new Error(error.message)
})
}
45 changes: 45 additions & 0 deletions src/files/infrastructure/FileJSDataverseRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { JSFilesCountInfoMapper } from './mappers/JSFilesCountInfoMapper'
import { JSFileMetadataMapper } from './mappers/JSFileMetadataMapper'
import { FilePermissions } from '../domain/models/FilePermissions'
import { JSFilePermissionsMapper } from './mappers/JSFilePermissionsMapper'
import { FilesWithCount } from '../domain/models/FilesWithCount'
import { FileHolder } from '../domain/repositories/File'

const includeDeaccessioned = true
Expand Down Expand Up @@ -77,6 +78,50 @@ export class FileJSDataverseRepository implements FileRepository {
})
}

getAllByDatasetPersistentIdWithCount(
datasetPersistentId: string,
datasetVersion: DatasetVersion,
paginationInfo: FilePaginationInfo = new FilePaginationInfo(),
criteria: FileCriteria = new FileCriteria()
): Promise<FilesWithCount> {
return getDatasetFiles
.execute(
datasetPersistentId,
datasetVersion.number.toString(),
includeDeaccessioned,
paginationInfo.pageSize,
paginationInfo.offset,
DomainFileMapper.toJSFileSearchCriteria(criteria),
DomainFileMapper.toJSFileOrderCriteria(criteria.sortBy)
)
.then((jsFilesSubset) =>
Promise.all([
jsFilesSubset.files,
jsFilesSubset.totalFilesCount,
FileJSDataverseRepository.getAllDownloadCount(jsFilesSubset.files),
FileJSDataverseRepository.getAllThumbnails(jsFilesSubset.files),
FileJSDataverseRepository.getAllWithPermissions(jsFilesSubset.files),
FileJSDataverseRepository.getAllTabularData(jsFilesSubset.files)
])
)
.then(([jsFiles, totalFilesCount, downloadCounts, thumbnails, permissions, tabularData]) => {
const mappedFiles = jsFiles.map((jsFile, index) =>
JSFileMapper.toFilePreview(
jsFile,
datasetVersion,
downloadCounts[index],
permissions[index],
thumbnails[index],
tabularData[index]
)
)
return { files: mappedFiles, totalFilesCount }
})
.catch((error: ReadError) => {
throw new Error(error.message)
})
}

private static getAllTabularData(jsFiles: JSFile[]): Promise<(FileTabularData | undefined)[]> {
return Promise.all(
jsFiles.map((jsFile) =>
Expand Down
22 changes: 16 additions & 6 deletions src/sections/dataset/Dataset.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@ import { SeparationLine } from '../shared/layout/SeparationLine/SeparationLine'
import { BreadcrumbsGenerator } from '../shared/hierarchy/BreadcrumbsGenerator'
import { useAlertContext } from '../alerts/AlertContext'
import { AlertMessageKey } from '../../alert/domain/models/Alert'
import { DatasetFilesScrollable } from './dataset-files/DatasetFilesScrollable'

interface DatasetProps {
fileRepository: FileRepository
created?: boolean
filesTabInfiniteScrollEnabled?: boolean
}

export function Dataset({ fileRepository, created }: DatasetProps) {
export function Dataset({ fileRepository, created, filesTabInfiniteScrollEnabled }: DatasetProps) {
const { setIsLoading } = useLoading()
const { dataset, isLoading } = useDataset()
const { t } = useTranslation('dataset')
Expand Down Expand Up @@ -82,11 +84,19 @@ export function Dataset({ fileRepository, created }: DatasetProps) {
<Tabs defaultActiveKey="files">
<Tabs.Tab eventKey="files" title={t('filesTabTitle')}>
<div className={styles['tab-container']}>
<DatasetFiles
filesRepository={fileRepository}
datasetPersistentId={dataset.persistentId}
datasetVersion={dataset.version}
/>
{filesTabInfiniteScrollEnabled ? (
<DatasetFilesScrollable
filesRepository={fileRepository}
datasetPersistentId={dataset.persistentId}
datasetVersion={dataset.version}
/>
) : (
<DatasetFiles
filesRepository={fileRepository}
datasetPersistentId={dataset.persistentId}
datasetVersion={dataset.version}
/>
)}
</div>
</Tabs.Tab>
<Tabs.Tab eventKey="metadata" title={t('metadataTabTitle')}>
Expand Down
12 changes: 10 additions & 2 deletions src/sections/dataset/DatasetFactory.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { MultipleFileDownloadProvider } from '../file/multiple-file-download/Mul
import { NotImplementedModalProvider } from '../not-implemented/NotImplementedModalProvider'
import { AlertProvider } from '../alerts/AlertProvider'
import { searchParamVersionToDomainVersion } from '../../Router'
import { FILES_TAB_INFINITE_SCROLL_ENABLED } from './config'

const datasetRepository = new DatasetJSDataverseRepository()
const fileRepository = new FileJSDataverseRepository()
Expand Down Expand Up @@ -61,7 +62,10 @@ function DatasetWithSearchParams() {
<DatasetProvider
repository={datasetRepository}
searchParams={{ privateUrlToken: privateUrlToken }}>
<Dataset fileRepository={fileRepository} />
<Dataset
fileRepository={fileRepository}
filesTabInfiniteScrollEnabled={FILES_TAB_INFINITE_SCROLL_ENABLED}
/>
</DatasetProvider>
)
}
Expand All @@ -70,7 +74,11 @@ function DatasetWithSearchParams() {
<DatasetProvider
repository={datasetRepository}
searchParams={{ persistentId: persistentId, version: version }}>
<Dataset fileRepository={fileRepository} created={created} />
<Dataset
fileRepository={fileRepository}
created={created}
filesTabInfiniteScrollEnabled={FILES_TAB_INFINITE_SCROLL_ENABLED}
/>
</DatasetProvider>
)
}
1 change: 1 addition & 0 deletions src/sections/dataset/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const FILES_TAB_INFINITE_SCROLL_ENABLED = true
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
.files-scrollable-container {
min-height: 400px;
max-height: 650px;
overflow-y: auto;

&--empty {
min-height: auto;
}

.criteria-form-container {
position: sticky;
top: 0;
z-index: 2;
padding: 0.25rem 0.25rem 1rem;
background: var(--bs-white);
}
}
Loading

0 comments on commit 107aaca

Please sign in to comment.