Skip to content

Commit

Permalink
Merge pull request #375 from IQSS/feature/file-upload-page-boilerplate
Browse files Browse the repository at this point in the history
Feature/file upload page boilerplate
  • Loading branch information
GPortas authored Apr 23, 2024
2 parents b17114a + 29a3023 commit 35f1747
Show file tree
Hide file tree
Showing 10 changed files with 201 additions and 19 deletions.
1 change: 1 addition & 0 deletions packages/design-system/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
- **FormSelect:** ability to forward react ref to input.
- **FormTextArea:** ability to forward react ref to input.
- **FormFeedback:** remove `span: 9` from styles.
- **DropdownButtonItem:** extend Props Interface to accept `as` prop.

# [1.1.0](https://github.com/IQSS/dataverse-frontend/compare/@iqss/dataverse-design-system@1.0.1...@iqss/dataverse-design-system@1.1.0) (2024-03-12)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { Dropdown as DropdownBS } from 'react-bootstrap'
import React, { ReactNode } from 'react'
import React, { ElementType, ReactNode } from 'react'

interface DropdownItemProps extends React.HTMLAttributes<HTMLElement> {
href?: string
eventKey?: string
disabled?: boolean
download?: string
children: ReactNode
as?: ElementType
}

export function DropdownButtonItem({
Expand All @@ -15,6 +16,7 @@ export function DropdownButtonItem({
disabled,
download,
children,
as,
...props
}: DropdownItemProps) {
return (
Expand All @@ -23,6 +25,7 @@ export function DropdownButtonItem({
eventKey={eventKey}
disabled={disabled}
download={download}
as={as}
{...props}>
{children}
</DropdownBS.Item>
Expand Down
5 changes: 5 additions & 0 deletions src/Router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { PageNotFound } from './sections/page-not-found/PageNotFound'
import { CreateDatasetFactory } from './sections/create-dataset/CreateDatasetFactory'
import { FileFactory } from './sections/file/FileFactory'
import { CollectionFactory } from './sections/collection/CollectionFactory'
import { UploadDatasetFilesFactory } from './sections/upload-dataset-files/UploadDatasetFilesFactory'
import { DatasetNonNumericVersion } from './dataset/domain/models/Dataset'

const router = createBrowserRouter(
Expand All @@ -31,6 +32,10 @@ const router = createBrowserRouter(
path: Route.CREATE_DATASET,
element: CreateDatasetFactory.create()
},
{
path: Route.UPLOAD_DATASET_FILES,
element: UploadDatasetFilesFactory.create()
},
{
path: Route.FILES,
element: FileFactory.create()
Expand Down
1 change: 1 addition & 0 deletions src/sections/Route.enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export enum Route {
LOG_OUT = '/',
DATASETS = '/datasets',
CREATE_DATASET = '/datasets/create',
UPLOAD_DATASET_FILES = '/datasets/upload-files',
FILES = '/files',
COLLECTIONS = '/collections'
}
Original file line number Diff line number Diff line change
@@ -1,45 +1,76 @@
import { useTranslation } from 'react-i18next'
import { useNavigate } from 'react-router-dom'
import { Dataset } from '../../../../dataset/domain/models/Dataset'
import { DropdownButton, DropdownButtonItem } from '@iqss/dataverse-design-system'
import { EditDatasetPermissionsMenu } from './EditDatasetPermissionsMenu'
import { DeleteDatasetButton } from './DeleteDatasetButton'
import { DeaccessionDatasetButton } from './DeaccessionDatasetButton'
import { useTranslation } from 'react-i18next'
import { useNotImplementedModal } from '../../../not-implemented/NotImplementedModalContext'
import { useSession } from '../../../session/SessionContext'
import { Route } from '../../../Route.enum'

interface EditDatasetMenuProps {
dataset: Dataset
}

enum EditDatasetMenuItems {
FILES_UPLOAD = 'filesUpload',
METADATA = 'metadata',
TERMS = 'terms',
PERMISSIONS = 'permissions',
PRIVATE_URL = 'privateUrl',
THUMBNAILS_PLUS_WIDGETS = 'thumbnailsPlusWidgets'
}

export function EditDatasetMenu({ dataset }: EditDatasetMenuProps) {
const { user } = useSession()
const { showModal } = useNotImplementedModal()
const { t } = useTranslation('dataset')
const navigate = useNavigate()

const handleOnSelect = (eventKey: EditDatasetMenuItems | string | null) => {
if (eventKey === EditDatasetMenuItems.FILES_UPLOAD) {
navigate(`${Route.UPLOAD_DATASET_FILES}?persistentId=${dataset.persistentId}`)
return
}
showModal()
}

if (!user || !dataset.permissions.canUpdateDataset) {
return <></>
}
const { showModal } = useNotImplementedModal()
const { t } = useTranslation('dataset')

return (
<DropdownButton
onSelect={showModal}
onSelect={handleOnSelect}
id={`edit-dataset-menu`}
title={t('datasetActionButtons.editDataset.title')}
asButtonGroup
variant="secondary"
disabled={dataset.checkIsLockedFromEdits(user.persistentId)}>
<DropdownButtonItem disabled={!dataset.hasValidTermsOfAccess}>
<DropdownButtonItem
eventKey={EditDatasetMenuItems.FILES_UPLOAD}
as="button"
disabled={!dataset.hasValidTermsOfAccess}>
{t('datasetActionButtons.editDataset.filesUpload')}
</DropdownButtonItem>
<DropdownButtonItem disabled={!dataset.hasValidTermsOfAccess}>
<DropdownButtonItem
eventKey={EditDatasetMenuItems.METADATA}
as="button"
disabled={!dataset.hasValidTermsOfAccess}>
{t('datasetActionButtons.editDataset.metadata')}
</DropdownButtonItem>
<DropdownButtonItem>{t('datasetActionButtons.editDataset.terms')}</DropdownButtonItem>
<DropdownButtonItem eventKey={EditDatasetMenuItems.TERMS} as="button">
{t('datasetActionButtons.editDataset.terms')}
</DropdownButtonItem>
<EditDatasetPermissionsMenu dataset={dataset} />
{(dataset.permissions.canManageDatasetPermissions ||
dataset.permissions.canManageFilesPermissions) && (
<DropdownButtonItem>{t('datasetActionButtons.editDataset.privateUrl')}</DropdownButtonItem>
<DropdownButtonItem eventKey={EditDatasetMenuItems.PRIVATE_URL} as="button">
{t('datasetActionButtons.editDataset.privateUrl')}
</DropdownButtonItem>
)}
<DropdownButtonItem>
<DropdownButtonItem eventKey={EditDatasetMenuItems.THUMBNAILS_PLUS_WIDGETS} as="button">
{t('datasetActionButtons.editDataset.thumbnailsPlusWidgets')}
</DropdownButtonItem>
<DeleteDatasetButton dataset={dataset} />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,26 @@
import { Button } from '@iqss/dataverse-design-system'
import { useNavigate } from 'react-router-dom'
import { useTranslation } from 'react-i18next'
import { PlusLg } from 'react-bootstrap-icons'
import { Button } from '@iqss/dataverse-design-system'
import { useSession } from '../../../session/SessionContext'
import styles from './DatasetUploadFilesButton.module.scss'
import { useTranslation } from 'react-i18next'
import { useDataset } from '../../DatasetContext'
import { useNotImplementedModal } from '../../../not-implemented/NotImplementedModalContext'
import { Route } from '../../../Route.enum'
import styles from './DatasetUploadFilesButton.module.scss'

export function DatasetUploadFilesButton() {
const { t } = useTranslation('dataset')
const { user } = useSession()
const { dataset } = useDataset()
const handleClick = () => {
// TODO - Implement upload files
showModal()
}
const { showModal } = useNotImplementedModal()
const navigate = useNavigate()

if (!user || !dataset?.permissions.canUpdateDataset) {
return <></>
}

const handleClick = () => {
navigate(`${Route.UPLOAD_DATASET_FILES}?persistentId=${dataset.persistentId}`)
}

return (
<Button
type="button"
Expand Down
40 changes: 40 additions & 0 deletions src/sections/upload-dataset-files/UploadDatasetFiles.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { useEffect } from 'react'
import { FileRepository } from '../../files/domain/repositories/FileRepository'
import { useLoading } from '../loading/LoadingContext'
import { useDataset } from '../dataset/DatasetContext'
import { PageNotFound } from '../page-not-found/PageNotFound'
import { BreadcrumbsGenerator } from '../shared/hierarchy/BreadcrumbsGenerator'

interface UploadDatasetFilesProps {
fileRepository: FileRepository
}

export const UploadDatasetFiles = ({
fileRepository: _fileRepository
}: UploadDatasetFilesProps) => {
const { setIsLoading } = useLoading()
const { dataset, isLoading } = useDataset()

useEffect(() => {
setIsLoading(isLoading)
}, [isLoading])

if (isLoading) {
return <p>Temporary Loading until having shape of skeleton</p>
}

return (
<>
{!dataset ? (
<PageNotFound />
) : (
<>
<BreadcrumbsGenerator hierarchy={dataset.hierarchy} />
<article>
<p>Metadata Files uploading goes here</p>
</article>
</>
)}
</>
)
}
26 changes: 26 additions & 0 deletions src/sections/upload-dataset-files/UploadDatasetFilesFactory.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { ReactElement } from 'react'
import { useSearchParams } from 'react-router-dom'
import { DatasetJSDataverseRepository } from '../../dataset/infrastructure/repositories/DatasetJSDataverseRepository'
import { FileJSDataverseRepository } from '../../files/infrastructure/FileJSDataverseRepository'
import { DatasetProvider } from '../dataset/DatasetProvider'
import { UploadDatasetFiles } from './UploadDatasetFiles'

const datasetRepository = new DatasetJSDataverseRepository()
const fileRepository = new FileJSDataverseRepository()

export class UploadDatasetFilesFactory {
static create(): ReactElement {
return <UploadDatasetFilesWithSearchParams />
}
}

function UploadDatasetFilesWithSearchParams() {
const [searchParams] = useSearchParams()
const persistentId = searchParams.get('persistentId') ?? undefined

return (
<DatasetProvider repository={datasetRepository} searchParams={{ persistentId: persistentId }}>
<UploadDatasetFiles fileRepository={fileRepository} />
</DatasetProvider>
)
}
24 changes: 24 additions & 0 deletions src/stories/upload-dataset-files/UploadDatasetFiles.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { Meta, StoryObj } from '@storybook/react'
import { WithI18next } from '../WithI18next'
import { WithLayout } from '../WithLayout'
import { UploadDatasetFiles } from '../../sections/upload-dataset-files/UploadDatasetFiles'
import { FileMockRepository } from '../file/FileMockRepository'
import { WithDataset } from '../dataset/WithDataset'

const meta: Meta<typeof UploadDatasetFiles> = {
title: 'Pages/Upload Dataset Files',
component: UploadDatasetFiles,
decorators: [WithI18next],
parameters: {
// Sets the delay for all stories.
chromatic: { delay: 15000, pauseAnimationAtEnd: true }
}
}

export default meta
type Story = StoryObj<typeof UploadDatasetFiles>

export const Default: Story = {
decorators: [WithLayout, WithDataset],
render: () => <UploadDatasetFiles fileRepository={new FileMockRepository()} />
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { DatasetRepository } from '../../../../src/dataset/domain/repositories/DatasetRepository'
import { DatasetMother } from '../../dataset/domain/models/DatasetMother'
import { FileRepository } from '../../../../src/files/domain/repositories/FileRepository'
import { Dataset as DatasetModel } from '../../../../src/dataset/domain/models/Dataset'
import { ReactNode } from 'react'
import { DatasetProvider } from '../../../../src/sections/dataset/DatasetProvider'
import { UploadDatasetFiles } from '../../../../src/sections/upload-dataset-files/UploadDatasetFiles'

const fileRepository: FileRepository = {} as FileRepository
const datasetRepository: DatasetRepository = {} as DatasetRepository

describe('Dataset', () => {
const mountWithDataset = (component: ReactNode, dataset: DatasetModel | undefined) => {
const searchParams = { persistentId: 'some-persistent-id' }
datasetRepository.getByPersistentId = cy.stub().resolves(dataset)

cy.customMount(
<DatasetProvider repository={datasetRepository} searchParams={searchParams}>
{component}
</DatasetProvider>
)
}

it('renders skeleton while loading', () => {
const testDataset = DatasetMother.create()

mountWithDataset(<UploadDatasetFiles fileRepository={fileRepository} />, testDataset)

cy.findByText('Temporary Loading until having shape of skeleton').should('exist')
cy.findByText(testDataset.version.title).should('not.exist')
})

it('renders page not found when dataset is null', () => {
const emptyDataset = DatasetMother.createEmpty()

mountWithDataset(<UploadDatasetFiles fileRepository={fileRepository} />, emptyDataset)

cy.findByText('Page Not Found').should('exist')
})

it('renders the breadcrumbs', () => {
const testDataset = DatasetMother.create()

mountWithDataset(<UploadDatasetFiles fileRepository={fileRepository} />, testDataset)

cy.findByText('Dataset Title').should('exist').should('have.class', 'active')
cy.findByRole('link', { name: 'Root' }).should('exist')
})
})

0 comments on commit 35f1747

Please sign in to comment.