Skip to content

Commit

Permalink
Merge branch 'develop' of https://github.com/IQSS/dataverse-frontend
Browse files Browse the repository at this point in the history
…into feature/229-basic-home-page-with-the-list-of-datasets
  • Loading branch information
MellyGray committed Dec 11, 2023
2 parents bf0760b + 333c7c6 commit ad04623
Show file tree
Hide file tree
Showing 34 changed files with 652 additions and 127 deletions.
39 changes: 39 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,45 @@

First install node >=16 and npm >=8. Recommended versions `node v19` and `npm v9`.

### Create a `.npmrc` file and add a token

To install the [@iqss/dataverse-client-javascript](https://github.com/IQSS/dataverse-client-javascript/pkgs/npm/dataverse-client-javascript)
from the GitHub registry, necessary for connecting with the Dataverse API, follow these steps to create an `.npmrc` file in
the root of your project using your GitHub token.

1. **Copy `.npmrc.example`**

Duplicate the `.npmrc.example` file in your project and save it as `.npmrc`.

2. **Replace the Token**

Open the newly created `.npmrc` file and replace `YOUR_GITHUB_TOKEN` with your actual GitHub token.

```plaintext
legacy-peer-deps=true
//npm.pkg.github.com/:_authToken=<YOUR_GITHUB_AUTH_TOKEN>
@iqss:registry=https://npm.pkg.github.com/
```

#### How to Get a GitHub Token

If you don't have a GitHub token yet, follow these steps:

1. Go to your GitHub account settings.

2. Navigate to "Developer settings" -> "Personal access tokens."

3. Click "Personal access tokens" -> "Tokens (classic)" -> "Generate new token (classic)".

4. Give the token a name and select the "read:packages" scope.

5. Copy the generated token.

6. Replace `YOUR_GITHUB_AUTH_TOKEN` in the `.npmrc` file with the copied token.

Now, you should be able to install the Dataverse JavaScript client using npm.

### `npm install`

Run this command to install the dependencies. You may see a message about vulnerabilities after running this command. \
Expand Down
1 change: 1 addition & 0 deletions dev.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ RUN npm run build

WORKDIR /usr/src/app
COPY package.json ./
COPY package-lock.json ./
COPY .npmrc ./
RUN npm install

Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"i18next": "22.4.9",
"i18next-browser-languagedetector": "7.0.1",
"i18next-http-backend": "2.1.1",
"moment-timezone": "^0.5.43",
"moment-timezone": "0.5.43",
"react-bootstrap": "2.7.2",
"react-bootstrap-icons": "1.10.3",
"react-i18next": "12.1.5",
Expand Down
36 changes: 24 additions & 12 deletions src/dataset/infrastructure/mappers/JSDatasetMapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
DatasetMetadataBlocks as JSDatasetMetadataBlocks,
DatasetMetadataFields as JSDatasetMetadataFields,
DatasetVersionInfo as JSDatasetVersionInfo,
DatasetUserPermissions as JSDatasetPermissions,
DatasetLock as JSDatasetLock
} from '@iqss/dataverse-client-javascript'
import { DatasetVersionState as JSDatasetVersionState } from '@iqss/dataverse-client-javascript/dist/datasets/domain/models/Dataset'
Expand All @@ -15,16 +16,18 @@ import {
DatasetMetadataFields,
DatasetVersion,
MetadataBlockName,
PrivateUrl,
DatasetPermissions,
DatasetLock,
DatasetLockReason
DatasetLockReason,
PrivateUrl
} from '../../domain/models/Dataset'

export class JSDatasetMapper {
static toDataset(
jsDataset: JSDataset,
citation: string,
summaryFieldsNames: string[],
jsDatasetPermissions: JSDatasetPermissions,
jsDatasetLocks: JSDatasetLock[],
requestedVersion?: string,
privateUrl?: PrivateUrl
Expand All @@ -41,19 +44,11 @@ export class JSDatasetMapper {
jsDataset.publicationDate,
jsDataset.citationDate
),
{
canDownloadFiles: true,
canUpdateDataset: true,
canPublishDataset: true,
canManageDatasetPermissions: true,
canManageFilesPermissions: true,
canDeleteDataset: true
}, // TODO Connect with dataset permissions
JSDatasetMapper.toDatasetPermissions(jsDatasetPermissions),
JSDatasetMapper.toLocks(jsDatasetLocks),
true, // TODO Connect with dataset hasValidTermsOfAccess
true, // TODO Connect with dataset isValid
jsDataset.versionInfo.releaseTime !== undefined &&
!isNaN(jsDataset.versionInfo.releaseTime.getTime()), // TODO Connect with dataset isReleased,
JSDatasetMapper.toIsReleased(jsDataset.versionInfo),
undefined, // TODO: get dataset thumbnail from Dataverse https://github.com/IQSS/dataverse-frontend/issues/203
privateUrl
).build()
Expand Down Expand Up @@ -190,6 +185,23 @@ export class JSDatasetMapper {
return extraFields
}

static toIsReleased(jsDatasetVersionInfo: JSDatasetVersionInfo): boolean {
return (
jsDatasetVersionInfo.releaseTime !== undefined &&
!isNaN(jsDatasetVersionInfo.releaseTime.getTime())
)
}

static toDatasetPermissions(jsDatasetPermissions: JSDatasetPermissions): DatasetPermissions {
return {
canDownloadFiles: true, // TODO: connect with js-dataverse
canUpdateDataset: jsDatasetPermissions.canEditDataset,
canPublishDataset: jsDatasetPermissions.canPublishDataset,
canManageDatasetPermissions: jsDatasetPermissions.canManageDatasetPermissions,
canManageFilesPermissions: true, // TODO: connect with js-dataverse DatasetPermissions.canManageFilesPermissions
canDeleteDataset: jsDatasetPermissions.canManageDatasetPermissions
}
}
static toLocks(jsDatasetLocks: JSDatasetLock[]): DatasetLock[] {
return jsDatasetLocks.map((jsDatasetLock) => {
return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import {
getDatasetCitation,
getDatasetSummaryFieldNames,
Dataset as JSDataset,
DatasetUserPermissions as JSDatasetPermissions,
getPrivateUrlDataset,
getPrivateUrlDatasetCitation,
getDatasetUserPermissions,
ReadError,
getDatasetLocks,
DatasetLock as JSDatasetLock
Expand All @@ -17,6 +19,8 @@ import { DatasetPaginationInfo } from '../../domain/models/DatasetPaginationInfo
import { DatasetPreview } from '../../domain/models/DatasetPreview'
import { DatasetPreviewMother } from '../../../../tests/component/dataset/domain/models/DatasetPreviewMother'

const includeDeaccessioned = true

export class DatasetJSDataverseRepository implements DatasetRepository {
// eslint-disable-next-line unused-imports/no-unused-vars
getAll(paginationInfo: DatasetPaginationInfo): Promise<DatasetPreview[]> {
Expand All @@ -43,26 +47,29 @@ export class DatasetJSDataverseRepository implements DatasetRepository {
requestedVersion?: string
): Promise<Dataset | undefined> {
return getDataset
.execute(persistentId, this.versionToVersionId(version))
.execute(persistentId, this.versionToVersionId(version), includeDeaccessioned)
.then((jsDataset) =>
Promise.all([
jsDataset,
getDatasetSummaryFieldNames.execute(),
getDatasetCitation.execute(jsDataset.id, this.versionToVersionId(version)),
getDatasetUserPermissions.execute(jsDataset.id),
getDatasetLocks.execute(jsDataset.id)
])
)
.then(
([jsDataset, summaryFieldsNames, citation, jsDatasetLocks]: [
([jsDataset, summaryFieldsNames, citation, jsDatasetPermissions, jsDatasetLocks]: [
JSDataset,
string[],
string,
JSDatasetPermissions,
JSDatasetLock[]
]) =>
JSDatasetMapper.toDataset(
jsDataset,
citation,
summaryFieldsNames,
jsDatasetPermissions,
jsDatasetLocks,
requestedVersion
)
Expand All @@ -80,10 +87,22 @@ export class DatasetJSDataverseRepository implements DatasetRepository {
getPrivateUrlDataset.execute(privateUrlToken),
getDatasetSummaryFieldNames.execute(),
getPrivateUrlDatasetCitation.execute(privateUrlToken)
]) // TODO - Add getDatasetLocks.execute(privateUrlToken) when it is available in js-dataverse
])
.then(([jsDataset, summaryFieldsNames, citation]: [JSDataset, string[], string]) =>
JSDatasetMapper.toDataset(jsDataset, citation, summaryFieldsNames, [])
)
JSDatasetMapper.toDataset(
jsDataset,
citation,
summaryFieldsNames,
{
canEditDataset: true,
canPublishDataset: true,
canManageDatasetPermissions: true,
canDeleteDatasetDraft: true,
canViewUnpublishedDataset: true
},
[]
)
) // TODO Connect with JS dataset permissions and getDatasetLocks.execute(privateUrlToken) when it is available in js-dataverse
.catch((error: ReadError) => {
throw new Error(error.message)
})
Expand Down
6 changes: 3 additions & 3 deletions src/files/domain/models/File.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ export class FileEmbargo {
export interface FileTabularData {
variablesCount: number
observationsCount: number
unf: string
unf?: string
}

export enum FileLabelType {
Expand Down Expand Up @@ -154,12 +154,12 @@ export class File {
readonly type: FileType,
readonly size: FileSize,
readonly date: FileDate,
public downloadCount: number,
readonly downloadCount: number,
readonly labels: FileLabel[],
public readonly isDeleted: boolean,
public readonly ingest: FileIngest,
readonly checksum?: FileChecksum,
public thumbnail?: string,
readonly thumbnail?: string,
readonly directory?: string,
readonly embargo?: FileEmbargo,
readonly tabularData?: FileTabularData,
Expand Down
68 changes: 38 additions & 30 deletions src/files/infrastructure/FileJSDataverseRepository.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { FileRepository } from '../domain/repositories/FileRepository'
import { File, FilePublishingStatus } from '../domain/models/File'
import { File } from '../domain/models/File'
import { FilesCountInfo } from '../domain/models/FilesCountInfo'
import { FileUserPermissions } from '../domain/models/FileUserPermissions'
import {
Expand All @@ -9,7 +9,10 @@ import {
getDatasetFilesTotalDownloadSize,
getFileDownloadCount,
getFileUserPermissions,
ReadError
ReadError,
File as JSFile,
getFileDataTables,
FileDataTable as JSFileTabularData
} from '@iqss/dataverse-client-javascript'
import { FileCriteria } from '../domain/models/FileCriteria'
import { DomainFileMapper } from './mappers/DomainFileMapper'
Expand All @@ -30,7 +33,6 @@ export class FileJSDataverseRepository implements FileRepository {
criteria: FileCriteria = new FileCriteria()
): Promise<File[]> {
const jsPagination = DomainFileMapper.toJSPagination(paginationInfo)

return getDatasetFiles
.execute(
datasetPersistentId,
Expand All @@ -41,48 +43,54 @@ export class FileJSDataverseRepository implements FileRepository {
DomainFileMapper.toJSFileSearchCriteria(criteria),
DomainFileMapper.toJSFileOrderCriteria(criteria.sortBy)
)
.then((jsFiles) => jsFiles.map((jsFile) => JSFileMapper.toFile(jsFile, datasetVersion)))
.then((files) => FileJSDataverseRepository.getAllWithDownloadCount(files))
.then((files) => FileJSDataverseRepository.getAllWithThumbnail(files))
.then((jsFiles) =>
Promise.all([
jsFiles,
FileJSDataverseRepository.getAllDownloadCount(jsFiles),
FileJSDataverseRepository.getAllThumbnails(jsFiles),
FileJSDataverseRepository.getAllTabularData(jsFiles)
])
)
.then(([jsFiles, downloadCounts, thumbnails, jsTabularData]) =>
jsFiles.map((jsFile, index) =>
JSFileMapper.toFile(
jsFile,
datasetVersion,
downloadCounts[index],
thumbnails[index],
jsTabularData[index]
)
)
)
.catch((error: ReadError) => {
throw new Error(error.message)
})
}

private static getAllWithDownloadCount(files: File[]): Promise<File[]> {
private static getAllTabularData(
jsFiles: JSFile[]
): Promise<(JSFileTabularData[] | undefined)[]> {
return Promise.all(
files.map((file) =>
FileJSDataverseRepository.getDownloadCountById(file.id, file.version.publishingStatus).then(
(downloadCount) => {
file.downloadCount = downloadCount
return file
}
)
jsFiles.map((jsFile) =>
jsFile.tabularData ? getFileDataTables.execute(jsFile.id) : undefined
)
)
}

private static getDownloadCountById(
id: number,
publishingStatus: FilePublishingStatus
): Promise<number> {
if (publishingStatus === FilePublishingStatus.RELEASED) {
return getFileDownloadCount.execute(id).then((downloadCount) => Number(downloadCount))
}
return Promise.resolve(0)
}

private static getAllWithThumbnail(files: File[]): Promise<File[]> {
private static getAllDownloadCount(jsFiles: JSFile[]): Promise<number[]> {
return Promise.all(
files.map((file) =>
FileJSDataverseRepository.getThumbnailById(file.id).then((thumbnail) => {
file.thumbnail = thumbnail
return file
})
jsFiles.map((jsFile) =>
jsFile.publicationDate
? getFileDownloadCount.execute(jsFile.id).then((downloadCount) => Number(downloadCount))
: 0
)
)
}

private static getAllThumbnails(jsFiles: JSFile[]): Promise<(string | undefined)[]> {
return Promise.all(jsFiles.map((jsFile) => this.getThumbnailById(jsFile.id)))
}

private static getThumbnailById(id: number): Promise<string | undefined> {
return fetch(`${this.DATAVERSE_BACKEND_URL}/api/access/datafile/${id}?imageThumb=400`)
.then((response) => {
Expand Down
Loading

0 comments on commit ad04623

Please sign in to comment.