Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/461 publish collection #500

Merged
merged 25 commits into from
Oct 10, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
26df4f4
feat: add publishCollection use case
ekraffmiller Sep 20, 2024
ecfd384
feat: add PublishDatasetModal component and Story
ekraffmiller Sep 21, 2024
b493f6e
test: add PublishCollectionModal.spec.tsx
ekraffmiller Sep 22, 2024
9fcf940
feat: add Publish Button to Collection page
ekraffmiller Sep 22, 2024
c1593e1
fix: add isReleased condition to display button
ekraffmiller Sep 22, 2024
c45a232
merge latest from develop
ekraffmiller Sep 23, 2024
76d4e39
fix: navigation to Collections page
ekraffmiller Sep 23, 2024
eeb3a8a
feat: add Published Alert to Collections page
ekraffmiller Sep 23, 2024
080b4f2
test: update component and e2e test
ekraffmiller Sep 23, 2024
df53089
fix: lint errors
ekraffmiller Sep 23, 2024
063b856
fix: json format
ekraffmiller Sep 23, 2024
f6f0882
test: add test that Publish Button doesn't exist
ekraffmiller Oct 1, 2024
13b56ee
format: add space
ekraffmiller Oct 1, 2024
5e2bd7c
fix: Publish button props
ekraffmiller Oct 1, 2024
47ac8bf
fix: render syntax
ekraffmiller Oct 1, 2024
6d1faab
feat: Add centered prop to Modal
ekraffmiller Oct 1, 2024
6732194
fix: Publish Modal appearance, Publish Button props, add translation
ekraffmiller Oct 1, 2024
b5e607f
Merge branch 'develop' into feat/461-publish-collection
ekraffmiller Oct 1, 2024
ac783ca
fix: translation label
ekraffmiller Oct 1, 2024
8694161
resolve merge conflicts
ekraffmiller Oct 3, 2024
43477b8
fix: collection.json formatting
ekraffmiller Oct 3, 2024
c20f84c
fix: Publish Button layout
ekraffmiller Oct 3, 2024
ae29873
test: add Unpublished to Collection.stories.tsx
ekraffmiller Oct 3, 2024
a9f576b
Update src/sections/collection/Collection.module.scss
ekraffmiller Oct 3, 2024
3ecad57
Merge branch 'develop' into feat/461-publish-collection
g-saracca Oct 10, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions public/locales/en/collection.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,11 @@
"authenticated": "This collection currently has no datasets. You can add to it by using the Add Data button on this page.",
"anonymous": "This collection currently has no datasets. Please <1>log in</1> to see if you are able to add to it."
},
"publish": {
"button": "Publish",
"question": "Are you sure you want to publish your collection? Once you do so it must remain published.",
"error": "There was an error publishing your collection."
},
"publishedAlert": "Your collection is now public.",
"createdAlert": "You have successfully created your collection! To learn more about what you can do with your collection, check out the <anchor>User Guide</anchor>."
}
4 changes: 3 additions & 1 deletion public/locales/en/shared.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
{
"asterisksIndicateRequiredFields": "Asterisks indicate required fields",
"remove": "Remove",
"add": "Add"
"add": "Add",
"cancel": "Cancel",
"continue": "Continue"
}
1 change: 1 addition & 0 deletions src/collection/domain/repositories/CollectionRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ export interface CollectionRepository {
create(collection: CollectionDTO, hostCollection?: string): Promise<number>
getFacets(collectionIdOrAlias: number | string): Promise<CollectionFacet[]>
getUserPermissions(collectionIdOrAlias: number | string): Promise<CollectionUserPermissions>
publish(collectionIdOrAlias: number | string): Promise<void>
}
10 changes: 10 additions & 0 deletions src/collection/domain/useCases/publishCollection.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { CollectionRepository } from '../repositories/CollectionRepository'

export function publishCollection(
collectionRepository: CollectionRepository,
id: string
): Promise<void> {
return collectionRepository.publish(id).catch((error: Error) => {
throw new Error(error.message)
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import {
createCollection,
getCollection,
getCollectionFacets,
getCollectionUserPermissions
getCollectionUserPermissions,
publishCollection
} from '@iqss/dataverse-client-javascript'
import { JSCollectionMapper } from '../mappers/JSCollectionMapper'
import { CollectionDTO } from '../../domain/useCases/DTOs/CollectionDTO'
Expand Down Expand Up @@ -33,4 +34,7 @@ export class CollectionJSDataverseRepository implements CollectionRepository {
.execute(collectionIdOrAlias)
.then((jsCollectionUserPermissions) => jsCollectionUserPermissions)
}
publish(collectionIdOrAlias: number | string): Promise<void> {
return publishCollection.execute(collectionIdOrAlias)
}
}
1 change: 1 addition & 0 deletions src/sections/Route.enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,6 @@ export const RouteWithParams = {
export enum QueryParamKey {
VERSION = 'version',
PERSISTENT_ID = 'persistentId',
COLLECTION_ID = 'collectionId',
QUERY = 'q'
}
17 changes: 15 additions & 2 deletions src/sections/collection/Collection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@ import { CollectionInfo } from './CollectionInfo'
import { Trans, useTranslation } from 'react-i18next'
import { useScrollTop } from '../../shared/hooks/useScrollTop'
import { useGetCollectionUserPermissions } from '../../shared/hooks/useGetCollectionUserPermissions'
import { PublishCollectionButton } from './PublishCollectionButton'

interface CollectionProps {
repository: CollectionRepository
datasetRepository: DatasetRepository
id: string
created: boolean
published: boolean
page?: number
infiniteScrollEnabled?: boolean
}
Expand All @@ -30,20 +32,21 @@ export function Collection({
id,
datasetRepository,
created,
published,
page,
infiniteScrollEnabled = false
}: CollectionProps) {
useScrollTop()
const { user } = useSession()
const { collection, isLoading } = useCollection(repository, id)
const { collection, isLoading } = useCollection(repository, id, published)
const { collectionUserPermissions } = useGetCollectionUserPermissions({
collectionIdOrAlias: id,
collectionRepository: repository
})

const canUserAddCollection = Boolean(collectionUserPermissions?.canAddCollection)
const canUserAddDataset = Boolean(collectionUserPermissions?.canAddDataset)

const canUserPublishCollection = user && Boolean(collectionUserPermissions?.canPublishCollection)
ekraffmiller marked this conversation as resolved.
Show resolved Hide resolved
const showAddDataActions = user && (canUserAddCollection || canUserAddDataset)

const { t } = useTranslation('collection')
Expand Down Expand Up @@ -78,6 +81,16 @@ export function Collection({
/>
</Alert>
)}
{published && (
<Alert variant="success" dismissible={false}>
{t('publishedAlert')}
</Alert>
)}
{!collection.isReleased && canUserPublishCollection && (
<div className={styles.container}>
<PublishCollectionButton repository={repository} collectionId={collection.id} />
</div>
)}
{showAddDataActions && (
<div className={styles.container}>
<AddDataActionsButton
Expand Down
4 changes: 3 additions & 1 deletion src/sections/collection/CollectionFactory.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ function CollectionWithSearchParams() {
const { collectionId = 'root' } = useParams<{ collectionId: string }>()
const location = useLocation()
const page = searchParams.get('page') ? parseInt(searchParams.get('page') as string) : undefined
const state = location.state as { created: boolean } | undefined
const state = location.state as { published: boolean; created: boolean } | undefined
const created = state?.created ?? false
const published = state?.published ?? false

return (
<Collection
Expand All @@ -28,6 +29,7 @@ function CollectionWithSearchParams() {
page={page}
id={collectionId}
created={created}
published={published}
infiniteScrollEnabled={INFINITE_SCROLL_ENABLED}
/>
)
Expand Down
41 changes: 41 additions & 0 deletions src/sections/collection/PublishCollectionButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { useTranslation } from 'react-i18next'
ekraffmiller marked this conversation as resolved.
Show resolved Hide resolved
import { useState } from 'react'
import { CollectionRepository } from '../../collection/domain/repositories/CollectionRepository'
import { PublishCollectionModal } from './publish-collection/PublishCollectionModal'
import { Button } from '@iqss/dataverse-design-system'
import { GlobeAmericas } from 'react-bootstrap-icons'
import styles from '../shared/add-data-actions/AddDataActionsButton.module.scss'

interface PublishCollectionButtonProps {
repository: CollectionRepository
collectionId: string
}
export function PublishCollectionButton({
repository,
collectionId
}: PublishCollectionButtonProps) {
const { t } = useTranslation('collection')
const [showModal, setShowModal] = useState(false)

const handleSelect = () => {
ekraffmiller marked this conversation as resolved.
Show resolved Hide resolved
setShowModal(true)
}

return (
<>
<PublishCollectionModal
show={showModal}
repository={repository}
collectionId={collectionId}
handleClose={() => setShowModal(false)}
/>
<Button
ekraffmiller marked this conversation as resolved.
Show resolved Hide resolved
icon={<GlobeAmericas className={styles.icon} />}
variant="secondary"
onClick={handleSelect}
type="submit">
ekraffmiller marked this conversation as resolved.
Show resolved Hide resolved
{t('publish.button')}
</Button>
</>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
@import "node_modules/@iqss/dataverse-design-system/src/lib/assets/styles/design-tokens/colors.module";

.errorText {
color: $dv-danger-color;
}

.warningText {
margin-bottom: 0;
color: $dv-warning-color;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { useTranslation } from 'react-i18next'
import { Button, Modal, Stack } from '@iqss/dataverse-design-system'
import { usePublishCollection } from './usePublishCollection'

import styles from './PublishCollectionModal.module.scss'
import { useNavigate } from 'react-router-dom'
import { CollectionRepository } from '../../../collection/domain/repositories/CollectionRepository'
import { SubmissionStatus } from '../../shared/form/DatasetMetadataForm/useSubmitDataset'
import { RouteWithParams } from '../../Route.enum'

interface PublishCollectionModalProps {
show: boolean
repository: CollectionRepository
collectionId: string
handleClose: () => void
}

export function PublishCollectionModal({
show,
repository,
collectionId,
handleClose
}: PublishCollectionModalProps) {
const { t: tShared } = useTranslation('shared')
const { t: tCollection } = useTranslation('collection')

const navigate = useNavigate()
const { submissionStatus, submitPublish, publishError } = usePublishCollection(
repository,
collectionId,
onPublishSucceed
)

function onPublishSucceed() {
navigate(RouteWithParams.COLLECTIONS(collectionId), {
state: { published: true }
})
handleClose()
}

return (
<Modal show={show} onHide={handleClose} size="xl">
ekraffmiller marked this conversation as resolved.
Show resolved Hide resolved
<Modal.Header>
<Modal.Title>Publish Collection</Modal.Title>
ekraffmiller marked this conversation as resolved.
Show resolved Hide resolved
</Modal.Header>
<Modal.Body>
<Stack direction="vertical">
<p className={styles.warningText}>{tCollection('publish.question')}</p>
<span className={styles.errorText}>
ekraffmiller marked this conversation as resolved.
Show resolved Hide resolved
{submissionStatus === SubmissionStatus.Errored &&
`${tCollection('publish.error')} ${publishError ? publishError : ''}`}
</span>
</Stack>
</Modal.Body>
<Modal.Footer>
<Button
variant="primary"
onClick={() => {
submitPublish()
ekraffmiller marked this conversation as resolved.
Show resolved Hide resolved
}}
type="submit">
{tShared('continue')}
</Button>
<Button
withSpacing
variant="secondary"
type="button"
onClick={handleClose}
disabled={submissionStatus === SubmissionStatus.IsSubmitting}>
{tShared('cancel')}
</Button>
</Modal.Footer>
</Modal>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { useState } from 'react'
import { CollectionRepository } from '../../../collection/domain/repositories/CollectionRepository'
import { publishCollection } from '../../../collection/domain/useCases/publishCollection'

import { SubmissionStatus } from '../../shared/form/DatasetMetadataForm/useSubmitDataset'

type UsePublishCollectionReturnType =
| {
submissionStatus:
| SubmissionStatus.NotSubmitted
| SubmissionStatus.IsSubmitting
| SubmissionStatus.SubmitComplete
submitPublish: () => void
publishError: null
}
| {
submissionStatus: SubmissionStatus.Errored
submitPublish: () => void
publishError: string
}

export function usePublishCollection(
repository: CollectionRepository,
collectionId: string,
onPublishSucceed: () => void
): UsePublishCollectionReturnType {
const [submissionStatus, setSubmissionStatus] = useState<SubmissionStatus>(
SubmissionStatus.NotSubmitted
)
const [publishError, setPublishError] = useState<string | null>(null)

const submitPublish = (): void => {
setSubmissionStatus(SubmissionStatus.IsSubmitting)

publishCollection(repository, collectionId)
.then(() => {
setPublishError(null)
setSubmissionStatus(SubmissionStatus.SubmitComplete)
onPublishSucceed()
return
})
.catch((err) => {
const errorMessage = err instanceof Error && err.message ? err.message : 'Unknown Error' // TODO: i18n

setPublishError(errorMessage)
setSubmissionStatus(SubmissionStatus.Errored)
})
}

return {
submissionStatus,
submitPublish,
publishError
} as UsePublishCollectionReturnType
}
10 changes: 7 additions & 3 deletions src/sections/collection/useCollection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@ import { Collection } from '../../collection/domain/models/Collection'
import { useEffect, useState } from 'react'
import { getCollectionById } from '../../collection/domain/useCases/getCollectionById'

export function useCollection(collectionRepository: CollectionRepository, collectionId: string) {
export function useCollection(
collectionRepository: CollectionRepository,
collectionId: string,
published?: boolean
) {
const [isLoading, setIsLoading] = useState(true)
const [collection, setCollection] = useState<Collection>()

useEffect(() => {
setIsLoading(true)

setCollection(undefined)
getCollectionById(collectionRepository, collectionId)
.then((collection: Collection | undefined) => {
setCollection(collection)
Expand All @@ -20,7 +24,7 @@ export function useCollection(collectionRepository: CollectionRepository, collec
.finally(() => {
setIsLoading(false)
})
}, [collectionRepository, collectionId])
}, [collectionRepository, collectionId, published])

return { collection, isLoading }
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ export function PublishDatasetMenu({ dataset, datasetRepository }: PublishDatase
}

const handleSelect = () => {
// TODO - Implement upload files
setShowModal(true)
}

Expand Down
Loading
Loading