Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
bc88046
feat: integrate use case & DeaccessionDatasetModal.tsx initial version
ekraffmiller Feb 24, 2025
1d3f46a
add form controls and component test
ekraffmiller Feb 26, 2025
e36cd0d
add DatasetDeaccessionDTO, and update modal form
ekraffmiller Feb 26, 2025
add4a4b
feat: add translations
ekraffmiller Mar 5, 2025
9f400d3
feat: add more implementation and unit tests
ekraffmiller Mar 6, 2025
a20e117
add ConfirmationModal.tsx, move form state management
ekraffmiller Mar 7, 2025
e1cdd18
fix: mapping of dataset.versionSummaries
ekraffmiller Mar 7, 2025
49adb84
fix: filter deaccessioned versions from list, hide NotImplementedModal
ekraffmiller Mar 7, 2025
3911864
fix: lint errors
ekraffmiller Mar 7, 2025
d322c33
fix: simplify submit form logic, remove console.log()
ekraffmiller Mar 7, 2025
023cdf1
fix: form details
ekraffmiller Mar 7, 2025
f908181
fix: refresh dataset after it is deaccessioned
ekraffmiller Mar 7, 2025
942de8e
fix: JSDatasetMapper.spec.ts, remove Promise.all() from useDeaccessio…
ekraffmiller Mar 11, 2025
38a6bbf
fix: FormGroupCheckbox.spec.tsx
ekraffmiller Mar 11, 2025
aa3ace1
fix: add unit tests
ekraffmiller Mar 12, 2025
f5e24ca
fix: add more unit tests
ekraffmiller Mar 12, 2025
ca0fb7b
fix: use PublicationStatus enum
ekraffmiller Mar 12, 2025
8c40ed6
resolve merge conflicts
ekraffmiller Mar 12, 2025
4e2e9fa
fix: increase size of ConfirmationModal and add Story
ekraffmiller Mar 24, 2025
8410118
fix: remove comment
ekraffmiller Mar 24, 2025
ccf0cc2
fix: remove comments and fix spacing
ekraffmiller Mar 24, 2025
0ddec32
fix: add default values to form for Story
ekraffmiller Mar 24, 2025
71f0e73
fix: add spacing
ekraffmiller Mar 24, 2025
90e8f03
fix: remove nested describe()
ekraffmiller Mar 24, 2025
a62b8c0
fix: EditDatasetMenu.stories.tsx
ekraffmiller Mar 24, 2025
2a988ce
fix: Remove extra DropdownButtonItem component, fix event handling
ekraffmiller Mar 24, 2025
02edcee
fix: Remove unused import
ekraffmiller Mar 24, 2025
919f0fc
fix: spacing and remove comments
ekraffmiller Mar 25, 2025
4dfa68c
resolve merge conflicts
ekraffmiller Mar 26, 2025
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
1,064 changes: 866 additions & 198 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"@dnd-kit/sortable": "8.0.0",
"@dnd-kit/utilities": "3.2.2",
"@faker-js/faker": "7.6.0",
"@iqss/dataverse-client-javascript": "2.0.0-alpha.26",
"@iqss/dataverse-client-javascript": "2.0.0-alpha.29",
"@iqss/dataverse-design-system": "*",
"@istanbuljs/nyc-config-typescript": "1.0.2",
"@tanstack/react-table": "8.9.2",
Expand Down Expand Up @@ -50,7 +50,6 @@
"react-toastify": "11.0.2",
"react-topbar-progress-indicator": "4.1.1",
"sass": "1.58.1",
"turndown": "7.2.0",
"typescript": "5.7.2",
"use-deep-compare": "1.2.1",
"vite-plugin-istanbul": "4.0.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export interface FormCheckboxProps
}

export const FormCheckbox = React.forwardRef(function FormCheckbox(
{ label, id, isValid, isInvalid, validFeedback, invalidFeedback, ...props }: FormCheckboxProps,
{ label, id, isValid, isInvalid, ...props }: FormCheckboxProps,
ref
) {
return (
Expand All @@ -25,8 +25,6 @@ export const FormCheckbox = React.forwardRef(function FormCheckbox(
{...props}
/>
<FormBS.Check.Label>{label}</FormBS.Check.Label>
<FormBS.Control.Feedback type="invalid">{invalidFeedback}</FormBS.Control.Feedback>
<FormBS.Control.Feedback type="valid">{validFeedback}</FormBS.Control.Feedback>
</FormBS.Check>
)
})
Original file line number Diff line number Diff line change
Expand Up @@ -71,38 +71,6 @@ describe('FormCheckbox', () => {
cy.findByText(tooltipMessage).should('be.visible')
})

it('renders with invalid feedback', () => {
cy.mount(
<FormCheckboxGroup title="Checkbox">
<FormGroup.Checkbox
id="checkbox-1"
label={option1Label}
name={checkboxName}
isInvalid
invalidFeedback="Invalid feedback"
/>
</FormCheckboxGroup>
)

cy.findByText('Invalid feedback').should('exist')
})

it('renders with valid feedback', () => {
cy.mount(
<FormCheckboxGroup title="Checkbox">
<FormGroup.Checkbox
id="checkbox-1"
label={option1Label}
name={checkboxName}
isValid
validFeedback="Valid feedback"
/>
</FormCheckboxGroup>
)

cy.findByText('Valid feedback').should('exist')
})

it('renders with invalid feedback as a group', () => {
cy.mount(
<FormCheckboxGroup title="Checkbox" isInvalid>
Expand Down
35 changes: 35 additions & 0 deletions public/locales/en/dataset.json
Original file line number Diff line number Diff line change
Expand Up @@ -181,5 +181,40 @@
"majorVersion": "Major Release",
"updateCurrentVersion": "Update Current Version (will permanently overwrite the latest published version)",
"error": "An error occurred while publishing the dataset."
},
"deaccession": {
"warning": "This dataset will no longer be public and a tombstone will display the reason for deaccessioning. Please read the <anchor>documentation</anchor> if you have any questions.",
"version": {
"label": "Which version(s) do you want to deaccession?",
"validation": "Please select at least one version to deaccession."
},
"reason": {
"label": "What is the reason for Deaccession?",
"validation": "Please select a reason for deaccessioning this dataset.",
"options": {
"identifiable": "There is identifiable data in one or more files.",
"retracted": "The research article has been retracted.",
"transferred": "The dataset has been transferred to another repository.",
"irb": "IRB request.",
"legalIssue": "Legal issue or Data Usage Agreement.",
"invalid": "Not a valid dataset."
}
},
"reasonOther": {
"label": "Please enter additional information about the reason for deaccession."
},
"forwardUrl": {
"label": "If applicable, please provide the URL where this dataset can be accessed after deaccessioning.",
"validation": "Please enter a valid URL."
}
},
"confirmDeaccession": {
"title": "Confirm Deaccession",
"message": "Are you sure you want to deaccession? This is permanent and the selected version(s) will no longer be viewable by the public.",
"reason": "Reason for deaccessioning:",
"reasonOther": "Additional information about the reason for deaccession:",
"forwardUrl": "URL where this dataset can be accessed after deaccessioning:",
"cancelButton": "Cancel",
"deaccessionButton": "Deaccession"
}
}
2 changes: 2 additions & 0 deletions public/locales/en/shared.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
"asterisksIndicateRequiredFields": "Asterisks indicate required fields",
"remove": "Remove",
"add": "Add",
"yes": "Yes",
"no": "No",
"cancel": "Cancel",
"close": "Close",
"continue": "Continue",
Expand Down
10 changes: 7 additions & 3 deletions src/dataset/domain/models/Dataset.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Alert, AlertMessageKey } from '../../../alert/domain/models/Alert'
import { UpwardHierarchyNode } from '../../../shared/hierarchy/domain/models/UpwardHierarchyNode'
import { FileDownloadSize } from '../../../files/domain/models/FileMetadata'
import { DatasetVersionSummaryInfo } from '@/dataset/domain/models/DatasetVersionSummaryInfo'

export enum DatasetLabelSemanticMeaning {
DATASET = 'dataset',
Expand Down Expand Up @@ -419,7 +420,8 @@ export class Dataset {
public readonly publicationDate?: string,
public readonly nextMajorVersion?: string,
public readonly nextMinorVersion?: string,
public readonly requiresMajorVersionUpdate?: boolean
public readonly requiresMajorVersionUpdate?: boolean,
public readonly versionsSummaries?: DatasetVersionSummaryInfo[]
) {}

public checkIsLockedFromPublishing(userPersistentId: string): boolean {
Expand Down Expand Up @@ -512,7 +514,8 @@ export class Dataset {
public readonly requestedVersion?: string,
public readonly nextMajorVersionNumber?: string,
public readonly nextMinorVersionNumber?: string,
public readonly requiresMajorVersionUpdate?: boolean
public readonly requiresMajorVersionUpdate?: boolean,
public readonly versionsSummaries?: DatasetVersionSummaryInfo[]
) {
this.withAlerts()
}
Expand Down Expand Up @@ -581,7 +584,8 @@ export class Dataset {
undefined,
this.nextMajorVersionNumber,
this.nextMinorVersionNumber,
this.requiresMajorVersionUpdate
this.requiresMajorVersionUpdate,
this.versionsSummaries
)
}
}
Expand Down
36 changes: 36 additions & 0 deletions src/dataset/domain/models/DatasetVersionSummaryInfo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
export interface DatasetVersionSummaryInfo {
id: number
versionNumber: string
summary?: DatasetVersionSummary | DatasetVersionSummaryStringValues
contributors: string
publishedOn?: string
}

export type DatasetVersionSummary = {
[key: string]: SummaryUpdates | SummaryUpdatesWithFields | FilesSummaryUpdates | boolean
}

interface SummaryUpdates {
added: number
deleted: number
changed: number
}

interface SummaryUpdatesWithFields {
[key: string]: SummaryUpdates
}

interface FilesSummaryUpdates {
added: number
removed: number
replaced: number
changedFileMetaData: number
changedVariableMetadata: number
}

export enum DatasetVersionSummaryStringValues {
firstPublished = 'firstPublished',
firstDraft = 'firstDraft',
versionDeaccessioned = 'versionDeaccessioned',
previousVersionDeaccessioned = 'previousVersionDeaccessioned'
}
7 changes: 7 additions & 0 deletions src/dataset/domain/repositories/DatasetRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { DatasetPaginationInfo } from '../models/DatasetPaginationInfo'
import { DatasetDTO } from '../useCases/DTOs/DatasetDTO'
import { DatasetsWithCount } from '../models/DatasetsWithCount'
import { VersionUpdateType } from '../models/VersionUpdateType'
import { DatasetDeaccessionDTO } from '../useCases/DTOs/DatasetDTO'

export interface DatasetRepository {
getByPersistentId: (
Expand All @@ -22,6 +23,12 @@ export interface DatasetRepository {

create: (dataset: DatasetDTO, collectionId: string) => Promise<{ persistentId: string }>
updateMetadata: (datasetId: string | number, datasetDTO: DatasetDTO) => Promise<void>
deaccession: (
datasetId: string | number,
version: string,
deaccessionDTO: DatasetDeaccessionDTO
) => Promise<void>

getAllWithCount: (
collectionId: string,
paginationInfo: DatasetPaginationInfo
Expand Down
5 changes: 5 additions & 0 deletions src/dataset/domain/useCases/DTOs/DatasetDTO.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,8 @@ type DatasetMetadataFieldValueDTO =
| DatasetMetadataChildFieldValueDTO[]

export type DatasetMetadataChildFieldValueDTO = Record<string, string>

export interface DatasetDeaccessionDTO {
deaccessionReason: string
deaccessionForwardURL?: string
}
13 changes: 13 additions & 0 deletions src/dataset/domain/useCases/deaccessionDataset.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { DatasetRepository } from '../repositories/DatasetRepository'
import { DatasetDeaccessionDTO } from '@iqss/dataverse-client-javascript'

export function deaccessionDataset(
datasetRepository: DatasetRepository,
datasetId: string | number,
version: string,
deaccessionDTO: DatasetDeaccessionDTO
): Promise<void> {
return datasetRepository.deaccession(datasetId, version, deaccessionDTO).catch((error: Error) => {
throw new Error(error.message)
})
}
7 changes: 5 additions & 2 deletions src/dataset/infrastructure/mappers/JSDatasetMapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import {
DatasetMetadataFields as JSDatasetMetadataFields,
DatasetUserPermissions as JSDatasetPermissions,
DatasetVersionDiff as JSDatasetVersionDiff,
DvObjectOwnerNode as JSUpwardHierarchyNode
DvObjectOwnerNode as JSUpwardHierarchyNode,
DatasetVersionSummaryInfo as JSDatasetVersionSummaryInfo
} from '@iqss/dataverse-client-javascript'
import { DatasetVersionDiff } from '../../domain/models/DatasetVersionDiff'
import {
Expand Down Expand Up @@ -43,6 +44,7 @@ export class JSDatasetMapper {
jsDatasetLocks: JSDatasetLock[],
jsDatasetFilesTotalOriginalDownloadSize: number,
jsDatasetFilesTotalArchivalDownloadSize: number,
jsDatasetVersionSummaries?: JSDatasetVersionSummaryInfo[],
requestedVersion?: string,
privateUrl?: PrivateUrl,
latestPublishedVersionMajorNumber?: number,
Expand Down Expand Up @@ -92,7 +94,8 @@ export class JSDatasetMapper {
latestPublishedVersionMajorNumber,
latestPublishedVersionMinorNumber
),
JSDatasetMapper.toRequiresMajorVersionUpdate(datasetVersionDiff)
JSDatasetMapper.toRequiresMajorVersionUpdate(datasetVersionDiff),
jsDatasetVersionSummaries
).build()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
DatasetVersionState,
FileDownloadSizeMode,
DatasetVersionDiff as JSDatasetVersionDiff,
DatasetVersionSummaryInfo as JSDatasetVersionSummaryInfo,
getAllDatasetPreviews,
getDataset,
getDatasetCitation,
Expand All @@ -24,9 +25,12 @@ import {
publishDataset,
ReadError,
updateDataset,
deaccessionDataset,
VersionUpdateType as JSVersionUpdateType,
WriteError,
getDatasetVersionDiff
getDatasetVersionDiff,
DatasetDeaccessionDTO,
getDatasetVersionsSummaries
} from '@iqss/dataverse-client-javascript'
import { JSDatasetMapper } from '../mappers/JSDatasetMapper'
import { DatasetPaginationInfo } from '../../domain/models/DatasetPaginationInfo'
Expand All @@ -37,7 +41,6 @@ import { DatasetsWithCount } from '../../domain/models/DatasetsWithCount'
import { VersionUpdateType } from '../../domain/models/VersionUpdateType'

const includeDeaccessioned = true
type DatasetDetails = [JSDataset, string[], string, JSDatasetPermissions, JSDatasetLock[]]

interface IDatasetDetails {
jsDataset: JSDataset
Expand All @@ -50,6 +53,7 @@ interface IDatasetDetails {
latestPublishedVersionMajorNumber?: number
latestPublishedVersionMinorNumber?: number
datasetVersionDiff?: JSDatasetVersionDiff
jsDatasetVersionsSummaries: JSDatasetVersionSummaryInfo[]
}

export class DatasetJSDataverseRepository implements DatasetRepository {
Expand Down Expand Up @@ -116,25 +120,32 @@ export class DatasetJSDataverseRepository implements DatasetRepository {
version?: string
): Promise<IDatasetDetails> {
return Promise.all([
jsDataset,
getDatasetSummaryFieldNames.execute(),
getDatasetCitation.execute(jsDataset.id, version, includeDeaccessioned),
getDatasetUserPermissions.execute(jsDataset.id),
getDatasetLocks.execute(jsDataset.id)
getDatasetLocks.execute(jsDataset.id),
getDatasetVersionsSummaries.execute(jsDataset.id)
]).then(
([
jsDataset,
summaryFieldsNames,
citation,
jsDatasetPermissions,
jsDatasetLocks
]: DatasetDetails) => {
jsDatasetLocks,
jsDatasetVersionsSummaries
]: [
string[],
string,
JSDatasetPermissions,
JSDatasetLock[],
JSDatasetVersionSummaryInfo[]
]) => {
return {
jsDataset,
summaryFieldsNames,
citation,
jsDatasetPermissions,
jsDatasetLocks,
jsDatasetVersionsSummaries,
jsDatasetFilesTotalOriginalDownloadSize: 0,
jsDatasetFilesTotalArchivalDownloadSize: 0
}
Expand Down Expand Up @@ -209,6 +220,7 @@ export class DatasetJSDataverseRepository implements DatasetRepository {
datasetDetails.jsDatasetLocks,
datasetDetails.jsDatasetFilesTotalOriginalDownloadSize,
datasetDetails.jsDatasetFilesTotalArchivalDownloadSize,
datasetDetails.jsDatasetVersionsSummaries,
requestedVersion,
undefined,
datasetDetails.latestPublishedVersionMajorNumber,
Expand Down Expand Up @@ -303,9 +315,6 @@ export class DatasetJSDataverseRepository implements DatasetRepository {
return publishDataset.execute(persistentId, jsVersionUpdateType).catch((error: WriteError) => {
throw new Error(error.message)
})
return publishDataset.execute(persistentId, jsVersionUpdateType).catch((error: WriteError) => {
throw new Error(error.message)
})
}

updateMetadata(datasetId: string | number, updatedDataset: DatasetDTO): Promise<void> {
Expand All @@ -315,4 +324,15 @@ export class DatasetJSDataverseRepository implements DatasetRepository {
throw new Error(error.message)
})
}
deaccession(
datasetId: string | number,
version: string,
deaccessionDTO: DatasetDeaccessionDTO
): Promise<void> {
return deaccessionDataset
.execute(datasetId, version, deaccessionDTO)
.catch((error: WriteError) => {
throw new Error(error.message)
})
}
}
4 changes: 3 additions & 1 deletion src/sections/dataset/DatasetContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import { Dataset } from '../../dataset/domain/models/Dataset'
interface DatasetContextProps {
dataset: Dataset | undefined
isLoading: boolean
refreshDataset: () => void
}
export const DatasetContext = createContext<DatasetContextProps>({
dataset: undefined,
isLoading: false
isLoading: false,
refreshDataset: () => {}
})

export const useDataset = () => useContext(DatasetContext)
Loading