Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
960 changes: 151 additions & 809 deletions package-lock.json

Large diffs are not rendered by default.

25 changes: 25 additions & 0 deletions public/locales/en/dataset.json
Original file line number Diff line number Diff line change
Expand Up @@ -216,5 +216,30 @@
"forwardUrl": "URL where this dataset can be accessed after deaccessioning:",
"cancelButton": "Cancel",
"deaccessionButton": "Deaccession"
},
"metrics": {
"title": "Dataset Metrics",
"tip": {
"default": "Aggregated metrics for this dataset.",
"makeDataCount": "Metrics collected using Make Data Count standards."
},
"makeDataCount": {
"title": "Make Data Count (MDC) Metrics",
"since": "since"
},
"downloads": {
"count": {
"default_zero": "{{count}} Downloads",
"default_one": "{{count}} Download",
"default_other": "{{count}} Downloads",
"preMDC_zero": "{{count}} Downloads pre-MDC",
"preMDC_one": "{{count}} Download pre-MDC",
"preMDC_other": "{{count}} Downloads pre-MDC"
},
"defaultTip": "Total aggregated downloads of files in this dataset.",
"preMakeDataCountTip": "Downloads prior to enabling MDC. Counts do not have the same filtering and detail as MDC metrics.",
"makeDataCountTip": "Each file downloaded is counted as 1, and added to the total download count."
},
"defaultGetDownloadCountError": "Something went wrong while getting the dataset download count. Try again later."
}
}
5 changes: 5 additions & 0 deletions src/dataset/domain/models/DatasetDownloadCount.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface DatasetDownloadCount {
id: number | string
downloadCount: number
MDCStartDate?: string
}
5 changes: 5 additions & 0 deletions src/dataset/domain/repositories/DatasetRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { DatasetDTO } from '../useCases/DTOs/DatasetDTO'
import { DatasetsWithCount } from '../models/DatasetsWithCount'
import { VersionUpdateType } from '../models/VersionUpdateType'
import { DatasetDeaccessionDTO } from '../useCases/DTOs/DatasetDTO'
import { DatasetDownloadCount } from '../models/DatasetDownloadCount'

export interface DatasetRepository {
getByPersistentId: (
Expand Down Expand Up @@ -38,4 +39,8 @@ export interface DatasetRepository {
paginationInfo: DatasetPaginationInfo
) => Promise<DatasetsWithCount>
publish(persistentId: string, versionUpdateType: VersionUpdateType): Promise<void>
getDownloadCount: (
datasetId: string | number,
includeMDC?: boolean
) => Promise<DatasetDownloadCount>
}
10 changes: 10 additions & 0 deletions src/dataset/domain/useCases/getDatasetDownloadCount.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { DatasetDownloadCount } from '../models/DatasetDownloadCount'
import { DatasetRepository } from '../repositories/DatasetRepository'

export async function getDatasetDownloadCount(
datasetRepository: DatasetRepository,
datasetId: string | number,
includeMDC?: boolean
): Promise<DatasetDownloadCount> {
return datasetRepository.getDownloadCount(datasetId, includeMDC)
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ import {
WriteError,
getDatasetVersionDiff,
DatasetDeaccessionDTO,
getDatasetVersionsSummaries
getDatasetVersionsSummaries,
getDatasetDownloadCount
} from '@iqss/dataverse-client-javascript'
import { JSDatasetMapper } from '../mappers/JSDatasetMapper'
import { DatasetPaginationInfo } from '../../domain/models/DatasetPaginationInfo'
Expand All @@ -39,6 +40,7 @@ import { DatasetDTO } from '../../domain/useCases/DTOs/DatasetDTO'
import { DatasetDTOMapper } from '../mappers/DatasetDTOMapper'
import { DatasetsWithCount } from '../../domain/models/DatasetsWithCount'
import { VersionUpdateType } from '../../domain/models/VersionUpdateType'
import { DatasetDownloadCount } from '@/dataset/domain/models/DatasetDownloadCount'

const includeDeaccessioned = true

Expand Down Expand Up @@ -339,4 +341,13 @@ export class DatasetJSDataverseRepository implements DatasetRepository {
throw new Error(error.message)
})
}

getDownloadCount(
datasetId: string | number,
includeMDC?: boolean
): Promise<DatasetDownloadCount> {
return getDatasetDownloadCount
.execute(datasetId, includeMDC)
.then((jsDatasetDownloadCount) => jsDatasetDownloadCount)
}
}
4 changes: 0 additions & 4 deletions src/sections/dataset/Dataset.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@
margin: 0.5rem 0;
}

.summary-container {
margin-bottom: 1em;
}

.tab-container {
padding: 1em 0;
}
25 changes: 13 additions & 12 deletions src/sections/dataset/Dataset.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { MetadataBlockInfoRepository } from '../../metadata-block-info/domain/re
import { CollectionRepository } from '../../collection/domain/repositories/CollectionRepository'
import { DatasetTerms } from '@/sections/dataset/dataset-terms/DatasetTerms'
import { ContactRepository } from '@/contact/domain/repositories/ContactRepository'
import { DatasetMetrics } from './dataset-metrics/DatasetMetrics'

interface DatasetProps {
datasetRepository: DatasetRepository
Expand Down Expand Up @@ -120,35 +121,35 @@ export function Dataset({
</Col>
</Row>
</div>

<header className={styles.header}>
<h1>{dataset.version.title}</h1>
<DatasetLabels labels={dataset.version.labels} />
</header>
<div className={styles.container}>
<Row>
<Col sm={9}>
<Col lg={9} className="mb-4">
<DatasetCitation thumbnail={dataset.thumbnail} version={dataset.version} />
<DatasetSummary
summaryFields={dataset.summaryFields}
license={dataset.license}
onCustomTermsClick={handleCustomTermsClick}
metadataBlockInfoRepository={metadataBlockInfoRepository}
/>
</Col>
<Col sm={3}>
<Col lg={3}>
<DatasetActionButtons
datasetRepository={datasetRepository}
collectionRepository={collectionRepository}
dataset={dataset}
contactRepository={contactRepository}
/>
</Col>
</Row>
<Row>
<Col sm={9} className={styles['summary-container']}>
<DatasetSummary
summaryFields={dataset.summaryFields}
license={dataset.license}
onCustomTermsClick={handleCustomTermsClick}
metadataBlockInfoRepository={metadataBlockInfoRepository}
<DatasetMetrics
datasetRepository={datasetRepository}
datasetId={dataset.persistentId}
/>
</Col>
</Row>

{publishInProgress && <TabsSkeleton />}

{(!publishInProgress || !isDatasetLoading) && (
Expand Down
35 changes: 35 additions & 0 deletions src/sections/dataset/dataset-metrics/DatasetMetrics.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
@use 'sass:color';
@import 'node_modules/@iqss/dataverse-design-system/src/lib/assets/styles/design-tokens/colors.module';

.dataset-metrics {
margin-bottom: 0.5rem;
border: solid 1px $dv-border-color;
border-radius: 4px;

.title {
display: flex;
flex-direction: column;
padding: 0.25rem 0.5rem;
background: color.adjust($dv-secondary-color, $alpha: -0.7);
border-bottom: solid 1px $dv-border-color;

span {
font-weight: 500;
}
}

.results {
display: flex;
flex-direction: column;
gap: 0.25rem;
padding: 0.25rem 0.5rem;
padding-left: 1rem;

.mdc-count {
display: flex;
flex-wrap: wrap;
gap: 0.25rem;
align-items: center;
}
}
}
118 changes: 118 additions & 0 deletions src/sections/dataset/dataset-metrics/DatasetMetrics.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { useTranslation } from 'react-i18next'
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton'
import { QuestionMarkTooltip } from '@iqss/dataverse-design-system'
import { DatasetRepository } from '@/dataset/domain/repositories/DatasetRepository'
import { useGetDatasetDownloadCount } from './useGetDatasetDownloadCount'
import styles from './DatasetMetrics.module.scss'

interface DatasetMetricsProps {
datasetRepository: DatasetRepository
datasetId: number | string
}

export const DatasetMetrics = ({ datasetRepository, datasetId }: DatasetMetricsProps) => {
const { t } = useTranslation('dataset')
const {
downloadCount: downloadCountIncludingMDC,
isLoadingDownloadCount: isLoadingDownloadCountIncludingMDC,
errorLoadingDownloadCount: errorLoadingDownloadCountIncludingMDC
} = useGetDatasetDownloadCount({ datasetRepository, datasetId, includeMDC: true })

const {
downloadCount: downloadCountNotIncludingMDC,
isLoadingDownloadCount: isLoadingDownloadCountNotIncludingMDC,
errorLoadingDownloadCount: errorLoadingDownloadCountNotIncludingMDC
} = useGetDatasetDownloadCount({ datasetRepository, datasetId, includeMDC: false })

const checkIsMDCenabled = (MDCStartDate: string | undefined): MDCStartDate is string => {
return typeof MDCStartDate === 'string' ? true : false
}

const isMDCenabled = checkIsMDCenabled(downloadCountIncludingMDC?.MDCStartDate)

if (isLoadingDownloadCountIncludingMDC || isLoadingDownloadCountNotIncludingMDC) {
return <DatasetMetricsSkeleton />
}

if (errorLoadingDownloadCountIncludingMDC || errorLoadingDownloadCountNotIncludingMDC) {
return null
}

return (
<div className={styles['dataset-metrics']}>
<div className={styles.title}>
{!isMDCenabled ? (
<span>
{t('metrics.title')}{' '}
<QuestionMarkTooltip placement="right" message={t('metrics.tip.default')} />
</span>
) : (
<>
<span>
{t('metrics.makeDataCount.title')}{' '}
<QuestionMarkTooltip placement="right" message={t('metrics.tip.makeDataCount')} />
</span>

<small>
<i>
{t('metrics.makeDataCount.since')} {downloadCountIncludingMDC.MDCStartDate}
</i>
</small>
</>
)}
</div>

<div className={styles.results}>
{!isMDCenabled && (
<span data-testid="classic-download-count">
{t('metrics.downloads.count.default', {
count: downloadCountNotIncludingMDC?.downloadCount
})}{' '}
<QuestionMarkTooltip placement="right" message={t('metrics.downloads.defaultTip')} />
</span>
)}

{/* If we received the MDCStartDate it means MDC is enabled and the count returned will be limited to the time prior to the MDCStartDate */}
{isMDCenabled && (
<div className={styles['mdc-count']} data-testid="mdc-download-count">
<span>
{t('metrics.downloads.count.default', {
count: downloadCountIncludingMDC.downloadCount
})}{' '}
<QuestionMarkTooltip
placement="right"
message={t('metrics.downloads.makeDataCountTip')}
/>
</span>

{/* If we have downloads before MDC was enabled, we show them also. */}
{downloadCountNotIncludingMDC && downloadCountNotIncludingMDC.downloadCount > 0 && (
<small>
{`(+${t('metrics.downloads.count.preMDC', {
count: downloadCountNotIncludingMDC.downloadCount
})})`}{' '}
<QuestionMarkTooltip
placement="right"
message={t('metrics.downloads.preMakeDataCountTip')}
/>
</small>
)}
</div>
)}
</div>
</div>
)
}

const DatasetMetricsSkeleton = () => (
<SkeletonTheme>
<div className={styles['dataset-metrics']} data-testid="dataset-metrics-skeleton">
<div className={styles.title}>
<Skeleton height={18} width={120} />
</div>
<div className={styles.results}>
<Skeleton height={18} width={100} />
</div>
</div>
</SkeletonTheme>
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { ReadError } from '@iqss/dataverse-client-javascript'
import { DatasetRepository } from '@/dataset/domain/repositories/DatasetRepository'
import { getDatasetDownloadCount } from '@/dataset/domain/useCases/getDatasetDownloadCount'
import { DatasetDownloadCount } from '@/dataset/domain/models/DatasetDownloadCount'
import { JSDataverseReadErrorHandler } from '@/shared/helpers/JSDataverseReadErrorHandler'

interface UseGetDatasetDownloadCountProps {
datasetRepository: DatasetRepository
datasetId: number | string
includeMDC: boolean
}

interface UseGetDatasetDownloadCountReturn {
downloadCount: DatasetDownloadCount | null
isLoadingDownloadCount: boolean
errorLoadingDownloadCount: string | null
}

export const useGetDatasetDownloadCount = ({
datasetRepository,
datasetId,
includeMDC
}: UseGetDatasetDownloadCountProps): UseGetDatasetDownloadCountReturn => {
const { t } = useTranslation('dataset')

const [downloadCount, setDownloadCount] = useState<DatasetDownloadCount | null>(null)

const [isLoadingDownloadCount, setIsLoadingDownloadCount] = useState<boolean>(true)
const [errorLoadingDownloadCount, setErrorLoadingDownloadCount] = useState<string | null>(null)

useEffect(() => {
const handleGetDownloadCount = async () => {
setIsLoadingDownloadCount(true)

try {
const res = await getDatasetDownloadCount(datasetRepository, datasetId, includeMDC)

setDownloadCount(res)
} catch (err: ReadError | unknown) {
if (err instanceof ReadError) {
const error = new JSDataverseReadErrorHandler(err)
const formattedError =
error.getReasonWithoutStatusCode() ?? /* istanbul ignore next */ error.getErrorMessage()

setErrorLoadingDownloadCount(formattedError)
} else {
setErrorLoadingDownloadCount(t('defaultGetDownloadCountError'))
}
} finally {
setIsLoadingDownloadCount(false)
}
}
void handleGetDownloadCount()
}, [datasetRepository, datasetId, includeMDC, t])

return {
downloadCount,
isLoadingDownloadCount,
errorLoadingDownloadCount
}
}
Loading
Loading