Skip to content

Commit

Permalink
feat(FilesTableFilters): add UI component for the Filter By Type
Browse files Browse the repository at this point in the history
  • Loading branch information
MellyGray committed Jul 11, 2023
1 parent d706827 commit 4d8bd1c
Show file tree
Hide file tree
Showing 17 changed files with 169 additions and 45 deletions.
15 changes: 14 additions & 1 deletion src/files/domain/models/File.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,26 @@ export interface FileLabel {
value: string
}

export class FileType {
constructor(readonly value: string) {}

toDisplayFormat(): string {
const words = this.value.split(' ')
return words
.map((word) => {
return word[0].toUpperCase() + word.substring(1)
})
.join(' ')
}
}

export class File {
constructor(
readonly id: string,
readonly version: FileVersion,
readonly name: string,
readonly access: FileAccess,
readonly type: string,
readonly type: FileType,
readonly size: FileSize,
readonly date: FileDate,
readonly downloads: number,
Expand Down
15 changes: 13 additions & 2 deletions src/files/domain/models/FileCriteria.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
export interface FileCriteria {
sortBy?: FileSortByOption
export class FileCriteria {
constructor(
public readonly sortBy: FileSortByOption = FileSortByOption.NAME_AZ,
public readonly filterByType: string = 'All'
) {}

withSortBy(sortBy: FileSortByOption): FileCriteria {
return new FileCriteria(sortBy, this.filterByType)
}

withFilterByType(filterByType: string): FileCriteria {
return new FileCriteria(this.sortBy, filterByType)
}
}

export enum FileSortByOption {
Expand Down
10 changes: 6 additions & 4 deletions src/sections/dataset/dataset-files/DatasetFiles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@ interface DatasetFilesProps {
datasetVersion?: string
}

const MINIMUM_FILES_TO_SHOW_CRITERIA_INPUTS = 2

export function DatasetFiles({
filesRepository,
datasetPersistentId,
datasetVersion
}: DatasetFilesProps) {
const [criteria, setCriteria] = useState<FileCriteria>()
const MINIMUM_FILES_TO_SHOW_CRITERIA_INPUTS = 2
const [criteria, setCriteria] = useState<FileCriteria>(new FileCriteria())

const { files, isLoading } = useFiles(
filesRepository,
datasetPersistentId,
Expand All @@ -28,7 +30,7 @@ export function DatasetFiles({
)
const { table, setFilesTableData } = useFilesTable()
const handleCriteriaChange = (newCriteria: FileCriteria) => {
setCriteria((criteria) => ({ ...criteria, ...newCriteria }))
setCriteria(newCriteria)
}

useEffect(() => {
Expand All @@ -42,7 +44,7 @@ export function DatasetFiles({
return (
<>
{files.length >= MINIMUM_FILES_TO_SHOW_CRITERIA_INPUTS && (
<FileCriteriaInputs onCriteriaChange={handleCriteriaChange} />
<FileCriteriaInputs criteria={criteria} onCriteriaChange={handleCriteriaChange} />
)}
<FilesTable table={table} />
</>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { FileCriteria } from '../../../../files/domain/models/FileCriteria'
import { DropdownButton, DropdownButtonItem } from 'dataverse-design-system'
import { FileType } from '../../../../files/domain/models/File'

export function FileCriteriaFilters({
criteria,
onCriteriaChange
}: {
criteria: FileCriteria
onCriteriaChange: (criteria: FileCriteria) => void
}) {
const totalFilesInfo = {
totalCount: 222,
countPerType: [
{
type: new FileType('text'),
count: 5
},
{
type: new FileType('image'),
count: 485
}
]
} // TODO: Get from API
const handleTypeChange = (eventKey: string | null) => {
onCriteriaChange(criteria.withFilterByType(eventKey as string))
}

return (
<>
<span>Filter by:</span>
<DropdownButton
id="files-table-filter-by-type"
title={`Filter Type: ${criteria.filterByType}`}
onSelect={handleTypeChange}
variant="secondary">
{/* TODO: All bold if selected*/}
<DropdownButtonItem eventKey="All">All</DropdownButtonItem>
{/* TODO: Add separator to design system*/}
{totalFilesInfo.countPerType.map(({ type, count }) => (
<DropdownButtonItem key={type.value} eventKey={type.value}>
{`${type.toDisplayFormat()} (${count})`}
</DropdownButtonItem>
))}
</DropdownButton>
</>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,22 @@ import { FileCriteria } from '../../../../files/domain/models/FileCriteria'
import { Col, Row } from 'dataverse-design-system'
import styles from './FileCriteriaInputs.module.scss'
import { FileCriteriaSortBy } from './FileCriteriaSortBy'
import { FileCriteriaFilters } from './FileCriteriaFilters'

export function FileCriteriaInputs({
criteria,
onCriteriaChange
}: {
criteria: FileCriteria
onCriteriaChange: (criteria: FileCriteria) => void
}) {
return (
<Row className={styles['criteria-section']}>
<Col>
<FileCriteriaFilters criteria={criteria} onCriteriaChange={onCriteriaChange} />
</Col>
<Col className={styles['sort-container']}>
<FileCriteriaSortBy onCriteriaChange={onCriteriaChange} />
<FileCriteriaSortBy criteria={criteria} onCriteriaChange={onCriteriaChange} />
</Col>
</Row>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ import { DropdownButton, DropdownButtonItem } from 'dataverse-design-system'
import { useTranslation } from 'react-i18next'

export function FileCriteriaSortBy({
criteria,
onCriteriaChange
}: {
criteria: FileCriteria
onCriteriaChange: (criteria: FileCriteria) => void
}) {
const { t } = useTranslation('files')
const handleSortChange = (eventKey: string | null) => {
onCriteriaChange({ sortBy: eventKey as FileSortByOption })
onCriteriaChange(criteria.withSortBy(eventKey as FileSortByOption))
}

return (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,16 @@
import { FileSize } from '../../../../../files/domain/models/File'
import { FileSize, FileType as FileTypeModel } from '../../../../../files/domain/models/File'

interface FileTypeProps {
type: string
type: FileTypeModel
size: FileSize
}

export function FileType({ type, size }: FileTypeProps) {
return (
<div>
<span>
{capitalizeFirstLetter(type)} - {size.toString()}
{type.toDisplayFormat()} - {size.toString()}
</span>
</div>
)
}

function capitalizeFirstLetter(str: string): string {
if (str.length === 0) {
return str
}
return str.charAt(0).toUpperCase() + str.slice(1)
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { FileThumbnailIcon } from './FileThumbnailIcon'
import { FileThumbnailPreviewImage } from './FileThumbnailPreviewImage'
import { FileAccess } from '../../../../../../files/domain/models/File'
import { FileAccess, FileType } from '../../../../../../files/domain/models/File'
import { FileThumbnailRestrictedIcon } from './FileThumbnailRestrictedIcon'

interface FileThumbnailProps {
thumbnail?: string | undefined
name: string
type: string
type: FileType
access: FileAccess
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import styles from './FileThumbnail.module.scss'
import { IconName } from 'dataverse-design-system'
import { FileType } from '../../../../../../files/domain/models/File'

const TYPE_TO_ICON: Record<string, IconName> = {
archive: IconName.PACKAGE,
Expand All @@ -19,8 +20,8 @@ const TYPE_TO_ICON: Record<string, IconName> = {
other: IconName.OTHER
}

export function FileThumbnailIcon({ type }: { type: string }) {
const icon = TYPE_TO_ICON[type] || TYPE_TO_ICON.default
export function FileThumbnailIcon({ type }: { type: FileType }) {
const icon = TYPE_TO_ICON[type.value] || TYPE_TO_ICON.default

return (
<div className={styles.container}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { faker } from '@faker-js/faker'
import { FileThumbnail } from '../../../../../../sections/dataset/dataset-files/files-table/file-info-cell/file-thumbnail/FileThumbnail'
import { WithI18next } from '../../../../../WithI18next'
import { FileMother } from '../../../../../../../tests/component/files/domain/models/FileMother'
import { FileType } from '../../../../../../files/domain/models/File'

const meta: Meta<typeof FileThumbnail> = {
title: 'Sections/Dataset Page/DatasetFiles/FilesTable/FileInfoCell/FileThumbnail',
Expand All @@ -16,7 +17,7 @@ type Story = StoryObj<typeof FileThumbnail>
export const WithIcon: Story = {
render: () => {
const file = FileMother.create({
type: 'some-type',
type: new FileType('some-type'),
access: { restricted: false, canDownload: true },
thumbnail: undefined
})
Expand Down
7 changes: 4 additions & 3 deletions tests/component/files/domain/models/FileMother.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
FileSize,
FileSizeUnit,
FileStatus,
FileType,
FileVersion
} from '../../../../../src/files/domain/models/File'

Expand Down Expand Up @@ -80,7 +81,7 @@ export class FileMother {
),
fileMockedData.name,
fileMockedData.access,
fileMockedData.type,
new FileType(fileMockedData.type as string),
new FileSize(fileMockedData.size.value, fileMockedData.size.unit),
fileMockedData.date,
fileMockedData.downloads,
Expand All @@ -100,7 +101,7 @@ export class FileMother {

static createDefault(props?: Partial<File>): File {
const defaultFile = {
type: 'file',
type: new FileType('file'),
version: {
majorNumber: 1,
minorNumber: 0,
Expand Down Expand Up @@ -145,7 +146,7 @@ export class FileMother {

static createWithTabularData(): File {
return this.createDefault({
type: 'tabular data',
type: new FileType('tabular data'),
tabularData: {
variablesCount: faker.datatype.number(100),
observationsCount: faker.datatype.number(100),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { FileMother } from '../../../files/domain/models/FileMother'
import { DatasetFiles } from '../../../../../src/sections/dataset/dataset-files/DatasetFiles'
import { FileRepository } from '../../../../../src/files/domain/repositories/FileRepository'
import { FileCriteria, FileSortByOption } from '../../../../../src/files/domain/models/FileCriteria'

const testFiles = FileMother.createMany(200)
const datasetPersistentId = 'test-dataset-persistent-id'
Expand Down Expand Up @@ -103,8 +104,10 @@ describe('DatasetFiles', () => {
'be.calledWith',
datasetPersistentId,
datasetVersion,
{ sortBy: 'name_az' }
new FileCriteria().withSortBy(FileSortByOption.NAME_AZ)
)

cy.findByRole('button', { name: 'Filter Type: All' }).should('exist')
})

it('does not render the files criteria inputs when there are less than 2 files', () => {
Expand All @@ -119,5 +122,6 @@ describe('DatasetFiles', () => {
)

cy.findByRole('button', { name: /Sort/ }).should('not.exist')
cy.findByRole('button', { name: 'Filter Type: All' }).should('not.exist')
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { FileCriteria } from '../../../../../../src/files/domain/models/FileCriteria'
import { FileCriteriaFilters } from '../../../../../../src/sections/dataset/dataset-files/file-criteria-inputs/FileCriteriaFilters'

const defaultCriteria = new FileCriteria()
describe('FilesCriteriaFilters', () => {
it('renders filter by type options', () => {
const onCriteriaChange = cy.stub().as('onCriteriaChange')

cy.customMount(
<FileCriteriaFilters criteria={defaultCriteria} onCriteriaChange={onCriteriaChange} />
)

cy.findByText('Filter by:').should('exist')

cy.findByRole('button', { name: 'Filter Type: All' }).click()

cy.findByText('All').should('exist')
cy.findByText('Image (485)').should('exist')
cy.findByText('Text (5)').should('exist')
})
})
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import { FileCriteriaInputs } from '../../../../../../src/sections/dataset/dataset-files/file-criteria-inputs/FileCriteriaInputs'
import { FileCriteria } from '../../../../../../src/files/domain/models/FileCriteria'

describe('FileCriteriaInputs', () => {
it('renders the SortBy input', () => {
const onCriteriaChange = cy.stub().as('onCriteriaChange')

cy.customMount(<FileCriteriaInputs onCriteriaChange={onCriteriaChange} />)
cy.customMount(
<FileCriteriaInputs criteria={new FileCriteria()} onCriteriaChange={onCriteriaChange} />
)

cy.findByRole('button', { name: /Sort/ }).should('exist')
})
Expand Down
Loading

0 comments on commit 4d8bd1c

Please sign in to comment.