Skip to content

Commit

Permalink
feat: single deposition page overview + table (#840)
Browse files Browse the repository at this point in the history
#774 

- various refactors to components to align with design
- hook up mock data to single deposition page table / overview
- create method summary section
  • Loading branch information
kne42 authored Jul 26, 2024
1 parent 20e8bc6 commit e48096b
Show file tree
Hide file tree
Showing 35 changed files with 1,393 additions and 221 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { render, screen } from '@testing-library/react'

import { AuthorInfo, MockAuthorLink } from 'app/components/AuthorLink'

import { DatasetAuthors } from './DatasetAuthors'
import { AuthorList } from './AuthorList'

const DEFAULT_AUTHORS: AuthorInfo[] = [
{ name: 'Foo', corresponding_author_status: true },
Expand All @@ -19,15 +19,15 @@ const AUTHOR_MAP = Object.fromEntries(
)

it('should render authors', () => {
render(<DatasetAuthors authors={DEFAULT_AUTHORS} />)
render(<AuthorList authors={DEFAULT_AUTHORS} />)

DEFAULT_AUTHORS.forEach((author) =>
expect(screen.getByText(author.name)).toBeInTheDocument(),
)
})

it('should sort primary authors', () => {
render(<DatasetAuthors authors={DEFAULT_AUTHORS} />)
render(<AuthorList authors={DEFAULT_AUTHORS} />)
const authorNode = screen.getByRole('paragraph')
const authors = (authorNode.textContent ?? '').split(', ')

Expand All @@ -36,7 +36,7 @@ it('should sort primary authors', () => {
})

it('should sort other authors', () => {
render(<DatasetAuthors authors={DEFAULT_AUTHORS} />)
render(<AuthorList authors={DEFAULT_AUTHORS} />)
const authorNode = screen.getByRole('paragraph')
const authors = (authorNode.textContent ?? '').split(', ')
const otherAuthors = authors.slice(2, -2)
Expand All @@ -48,7 +48,7 @@ it('should sort other authors', () => {
})

it('should sort corresponding authors', () => {
render(<DatasetAuthors authors={DEFAULT_AUTHORS} />)
render(<AuthorList authors={DEFAULT_AUTHORS} />)
const authorNode = screen.getByRole('paragraph')
const authors = (authorNode.textContent ?? '').split(', ')

Expand All @@ -66,9 +66,7 @@ it('should render author links', () => {
orcid: `0000-0000-0000-000${idx}`,
}))

render(
<DatasetAuthors authors={authors} AuthorLinkComponent={MockAuthorLink} />,
)
render(<AuthorList authors={authors} AuthorLinkComponent={MockAuthorLink} />)

authors.forEach((author) =>
expect(
Expand All @@ -84,7 +82,7 @@ it('should not render author links when compact', () => {
}))

render(
<DatasetAuthors
<AuthorList
authors={authors}
AuthorLinkComponent={MockAuthorLink}
compact
Expand All @@ -95,7 +93,7 @@ it('should not render author links when compact', () => {
})

it('should not render other authors when compact', () => {
render(<DatasetAuthors authors={DEFAULT_AUTHORS} compact />)
render(<AuthorList authors={DEFAULT_AUTHORS} compact />)
const authorNode = screen.getByRole('paragraph')
const authors = (authorNode.textContent ?? '').split(', ')
const otherAuthors = authors.slice(2, -2)
Expand All @@ -106,13 +104,13 @@ it('should not render other authors when compact', () => {
})

it('should render comma if compact and has corresponding authors', () => {
render(<DatasetAuthors authors={DEFAULT_AUTHORS} compact />)
render(<AuthorList authors={DEFAULT_AUTHORS} compact />)
expect(screen.getByText((text) => text.includes('... ,'))).toBeInTheDocument()
})

it('should not render comma for others if compact and no corresponding authors', () => {
render(
<DatasetAuthors
<AuthorList
authors={DEFAULT_AUTHORS.filter(
(author) => !author.corresponding_author_status,
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ function getAuthorIds(authors: AuthorInfo[]) {
return authors.map((author) => author.name + author.email + author.orcid)
}

export function DatasetAuthors({
export function AuthorList({
AuthorLinkComponent = AuthorLink,
authors,
className,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './AuthorList'
46 changes: 26 additions & 20 deletions frontend/packages/data-portal/app/components/Breadcrumbs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,37 +40,39 @@ function Breadcrumb({

export function Breadcrumbs({
variant,
dataset,
data,
}: {
variant: 'dataset' | 'run'
dataset: { id: number; title: string }
variant: 'dataset' | 'deposition' | 'run'
data: { id: number; title: string }
}) {
const { t } = useI18n()

const { browseDatasetHistory } = useBrowseDatasetFilterHistory()
const { singleDatasetHistory } = useSingleDatasetFilterHistory()

const browseAllLink = useMemo(() => {
const url = '/browse-data/datasets'
const encodedParams = encodeParams(
Array.from(browseDatasetHistory?.entries() ?? []),
)
const url =
variant === 'deposition'
? '/browse-data/depositions'
: '/browse-data/datasets'
const history = variant === 'deposition' ? undefined : browseDatasetHistory
const encodedParams = encodeParams(Array.from(history?.entries() ?? []))

return `${url}?${encodedParams}`
}, [browseDatasetHistory])
}, [browseDatasetHistory, variant])

const singleDatasetLink = useMemo(() => {
if (variant === 'dataset') {
return undefined
}

const url = `/datasets/${dataset.id}`
const url = `/datasets/${data.id}`
const encodedParams = encodeParams(
Array.from(singleDatasetHistory?.entries() ?? []),
)

return `${url}?${encodedParams}`
}, [singleDatasetHistory, variant, dataset])
}, [singleDatasetHistory, variant, data])

const chevronIcon = (
<SmallChevronRightIcon className="w-[8px] h-[8px] shrink-0" />
Expand All @@ -79,20 +81,24 @@ export function Breadcrumbs({
return (
<div className="flex flex-row gap-sds-s text-sds-body-s leading-sds-body-s text-sds-gray-black items-center whitespace-nowrap content-start">
<Breadcrumb
text={t('allDatasets')}
text={t(variant === 'deposition' ? 'allDepositions' : 'allDatasets')}
link={browseAllLink}
className="shrink-0"
/>
{chevronIcon}
<Breadcrumb
text={
variant === 'dataset'
? `${t('dataset')}`
: `${t('dataset')}: ${dataset.title}`
}
link={singleDatasetLink}
className="overflow-ellipsis overflow-hidden flex-initial"
/>
{variant === 'deposition' ? (
<Breadcrumb text={t('deposition')} />
) : (
<Breadcrumb
text={
variant === 'dataset'
? `${t('dataset')}`
: `${t('dataset')}: ${data.title}`
}
link={singleDatasetLink}
className="overflow-ellipsis overflow-hidden flex-initial"
/>
)}
{variant === 'run' && (
<>
{chevronIcon}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { range } from 'lodash-es'
import { useEffect, useMemo, useState } from 'react'

import { AnnotatedObjectsList } from 'app/components/AnnotatedObjectsList'
import { DatasetAuthors } from 'app/components/Dataset/DatasetAuthors'
import { AuthorList } from 'app/components/AuthorList'
import { I18n } from 'app/components/I18n'
import { KeyPhoto } from 'app/components/KeyPhoto'
import { Link } from 'app/components/Link'
Expand Down Expand Up @@ -170,7 +170,7 @@ export function DatasetTable() {
/>
</>
) : (
<DatasetAuthors authors={dataset.authors} compact />
<AuthorList authors={dataset.authors} compact />
)}
</p>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { range, sum } from 'lodash-es'
import { useMemo } from 'react'

import { AnnotatedObjectsList } from 'app/components/AnnotatedObjectsList'
import { DatasetAuthors } from 'app/components/Dataset/DatasetAuthors'
import { AuthorList } from 'app/components/AuthorList'
import { KeyPhoto } from 'app/components/KeyPhoto'
import { Link } from 'app/components/Link'
import { CellHeader, PageTable, TableCell } from 'app/components/Table'
Expand Down Expand Up @@ -147,7 +147,7 @@ export function DepositionTable() {
/>
</>
) : (
<DatasetAuthors authors={deposition.authors} compact />
<AuthorList authors={deposition.authors} compact />
)}
</p>
</div>
Expand Down
89 changes: 89 additions & 0 deletions frontend/packages/data-portal/app/components/CollapsibleList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { Icon } from '@czi-sds/components'
import { ReactNode, useState } from 'react'

import { useI18n } from 'app/hooks/useI18n'
import { cns } from 'app/utils/cns'

interface ListEntry {
key: string
entry: ReactNode
}

export function CollapsibleList({
entries,
collapseAfter,
tableVariant = false,
}: {
entries?: ListEntry[]
collapseAfter?: number
tableVariant?: boolean
}) {
const collapsible =
collapseAfter !== undefined &&
collapseAfter >= 0 &&
entries !== undefined &&
entries.length > collapseAfter + 1

const { t } = useI18n()
const [collapsed, setCollapsed] = useState(true)

return entries ? (
<ul
className={cns(
'flex flex-col gap-sds-xs',
'text-sds-body-xxs leading-sds-body-xxs text-sds-gray-600',
collapsible && 'transition-[max-height_0.2s_ease-out]',
)}
>
{entries.map(
({ key, entry }, i) =>
!(collapsible && collapsed && i + 1 > collapseAfter) && (
<li key={key}>{entry}</li>
),
)}
{collapsible && (
<div
className={cns(
'mt-sds-xxs font-semibold',
tableVariant && 'text-sds-primary-400',
)}
>
<button type="button" onClick={() => setCollapsed(!collapsed)}>
<span
className={cns(
'flex flex-row gap-sds-xxs items-center',
!tableVariant && 'capitalize',
)}
>
{collapsed ? (
<>
<Icon
sdsIcon="plus"
sdsSize="xs"
sdsType="static"
className="!text-current"
/>
{t('showMore', { count: entries.length - collapseAfter })}
</>
) : (
<>
<Icon
sdsIcon="minus"
sdsSize="xs"
sdsType="static"
className="!text-current"
/>
{t('showLess')}
</>
)}
</span>
</button>
</div>
)}
</ul>
) : (
<p className="text-sds-body-xxs leading-sds-body-xxs text-sds-gray-600">
{t('notSubmitted')}
</p>
)
}
20 changes: 20 additions & 0 deletions frontend/packages/data-portal/app/components/DatabaseList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { CollapsibleList } from 'app/components/CollapsibleList'
import { DatabaseEntry } from 'app/components/DatabaseEntry'

export function DatabaseList({
entries,
collapseAfter,
}: {
entries?: string[]
collapseAfter?: number
}) {
return (
<CollapsibleList
entries={entries?.map((e) => ({
key: e,
entry: <DatabaseEntry entry={e} />,
}))}
collapseAfter={collapseAfter}
/>
)
}
Loading

0 comments on commit e48096b

Please sign in to comment.