Skip to content
Draft
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
3 changes: 3 additions & 0 deletions dev-env/docker-compose-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ services:
-Ddataverse.files.s3.connection-pool-size=2048
-Ddataverse.files.s3.custom-endpoint-region=us-east-1
-Ddataverse.files.s3.custom-endpoint-url=https://s3.us-east-1.amazonaws.com
-Ddataverse.files.file1.type=file
-Ddataverse.files.file1.label=FileSystem
-Ddataverse.files.file1.storage-location=/dv/files/file1
# We publish the port on the host machine instead of just exposing it within the network, so that the browser can access the URLs of images generated by Dataverse (http://localhost:8080...).
# This is necessary because the dev_nginx proxy is placed on top of the Dataverse service, making those URLs unreachable unless this port is exposed.
# This workaround is only necessary and intended for the local dev environment and will not be used in the remote environment, where we use a production DNS.
Expand Down
8 changes: 4 additions & 4 deletions 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 @@ -18,7 +18,7 @@
"@dnd-kit/sortable": "8.0.0",
"@dnd-kit/utilities": "3.2.2",
"@faker-js/faker": "7.6.0",
"@iqss/dataverse-client-javascript": "2.1.0-alpha.4",
"@iqss/dataverse-client-javascript": "2.2.0-alpha.4",
"@iqss/dataverse-design-system": "*",
"@istanbuljs/nyc-config-typescript": "1.0.2",
"@tanstack/react-table": "8.9.2",
Expand Down
1 change: 1 addition & 0 deletions public/locales/en/collection.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"helpText": "Share this collection on your favorite social media networks."
},
"editedAlert": "You have successfully updated your collection!",
"storageDriverUpdateFailed": "The collection was created, but the storage driver could not be updated.",
"editCollection": {
"edit": "Edit",
"generalInfo": "General Information",
Expand Down
1 change: 1 addition & 0 deletions public/locales/es/collection.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"helpText": "Comparte esta colección en tus redes sociales favoritas."
},
"editedAlert": "¡Has actualizado tu colección correctamente!",
"storageDriverUpdateFailed": "La colección se creó, pero no se pudo actualizar el driver de almacenamiento.",
"editCollection": {
"edit": "Editar",
"generalInfo": "Información general",
Expand Down
1 change: 1 addition & 0 deletions src/collection/domain/models/AllowedStorageDrivers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type AllowedStorageDrivers = Record<string, string>
8 changes: 8 additions & 0 deletions src/collection/domain/models/StorageDriver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export interface StorageDriver {
name: string
type?: string
label?: string
directUpload: boolean
directDownload: boolean
uploadOutOfBand: boolean
}
8 changes: 8 additions & 0 deletions src/collection/domain/repositories/CollectionRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import { PublicationStatus } from '@/shared/core/domain/models/PublicationStatus
import { LinkingObjectType } from '../useCases/getCollectionsForLinking'
import { CollectionSummary } from '../models/CollectionSummary'
import { CollectionLinks } from '../models/CollectionLinks'
import { AllowedStorageDrivers } from '../models/AllowedStorageDrivers'
import { StorageDriver } from '../models/StorageDriver'

export interface CollectionRepository {
getById: (id?: string) => Promise<Collection>
Expand Down Expand Up @@ -58,4 +60,10 @@ export interface CollectionRepository {
linkingCollectionIdOrAlias: number | string
): Promise<void>
getLinks(collectionIdOrAlias: number | string): Promise<CollectionLinks>
getAllowedStorageDrivers(collectionIdOrAlias: number | string): Promise<AllowedStorageDrivers>
getStorageDriver(
collectionIdOrAlias: number | string,
getEffective?: boolean
): Promise<StorageDriver>
setStorageDriver(collectionIdOrAlias: number | string, driverLabel: string): Promise<string>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { AllowedStorageDrivers } from '../models/AllowedStorageDrivers'
import { CollectionRepository } from '../repositories/CollectionRepository'

export async function getCollectionAllowedStorageDrivers(
collectionRepository: CollectionRepository,
collectionIdOrAlias: number | string
): Promise<AllowedStorageDrivers> {
return collectionRepository.getAllowedStorageDrivers(collectionIdOrAlias)
}
10 changes: 10 additions & 0 deletions src/collection/domain/useCases/getCollectionStorageDriver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { StorageDriver } from '../models/StorageDriver'
import { CollectionRepository } from '../repositories/CollectionRepository'

export async function getCollectionStorageDriver(
collectionRepository: CollectionRepository,
collectionIdOrAlias: number | string,
getEffective?: boolean
): Promise<StorageDriver> {
return collectionRepository.getStorageDriver(collectionIdOrAlias, getEffective)
}
9 changes: 9 additions & 0 deletions src/collection/domain/useCases/setCollectionDriver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { CollectionRepository } from '../repositories/CollectionRepository'

export async function setCollectionDriver(
collectionRepository: CollectionRepository,
collectionIdOrAlias: number | string,
driverLabel: string
): Promise<string> {
return collectionRepository.setStorageDriver(collectionIdOrAlias, driverLabel)
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ import {
deleteCollectionFeaturedItem,
getCollectionsForLinking,
linkCollection,
getCollectionLinks
getCollectionLinks,
getAllowedCollectionStorageDrivers,
getCollectionStorageDriver,
setCollectionStorageDriver
} from '@iqss/dataverse-client-javascript'
import { JSCollectionMapper } from '../mappers/JSCollectionMapper'
import { CollectionDTO } from '../../domain/useCases/DTOs/CollectionDTO'
Expand All @@ -34,6 +37,8 @@ import { PublicationStatus } from '@/shared/core/domain/models/PublicationStatus
import { CollectionSummary } from '@/collection/domain/models/CollectionSummary'
import { LinkingObjectType } from '@/collection/domain/useCases/getCollectionsForLinking'
import { CollectionLinks } from '@/collection/domain/models/CollectionLinks'
import { AllowedStorageDrivers } from '@/collection/domain/models/AllowedStorageDrivers'
import { StorageDriver } from '@/collection/domain/models/StorageDriver'

export class CollectionJSDataverseRepository implements CollectionRepository {
getById(id?: string): Promise<Collection> {
Expand Down Expand Up @@ -174,4 +179,19 @@ export class CollectionJSDataverseRepository implements CollectionRepository {
getLinks(collectionIdOrAlias: number | string): Promise<CollectionLinks> {
return getCollectionLinks.execute(collectionIdOrAlias)
}

getAllowedStorageDrivers(collectionIdOrAlias: number | string): Promise<AllowedStorageDrivers> {
return getAllowedCollectionStorageDrivers.execute(collectionIdOrAlias)
}

getStorageDriver(
collectionIdOrAlias: number | string,
getEffective?: boolean
): Promise<StorageDriver> {
return getCollectionStorageDriver.execute(collectionIdOrAlias, getEffective)
}

setStorageDriver(collectionIdOrAlias: number | string, driverLabel: string): Promise<string> {
return setCollectionStorageDriver.execute(collectionIdOrAlias, driverLabel)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import { CollectionHelper } from '@/sections/collection/CollectionHelper'
import { MetadataFieldsHelper } from '../DatasetMetadataForm/MetadataFieldsHelper'
import { MetadataBlockInfo } from '@/metadata-block-info/domain/models/MetadataBlockInfo'
import { useCollectionRepositories } from '@/shared/contexts/repositories/RepositoriesProvider'
import { useGetCollectionAllowedStorageDrivers } from '@/shared/hooks/useGetCollectionAllowedStorageDrivers'
import { useGetCollectionStorageDriver } from '@/shared/hooks/useGetCollectionStorageDriver'

export const METADATA_BLOCKS_NAMES_GROUPER = 'metadataBlockNames'
export const USE_FIELDS_FROM_PARENT = 'useFieldsFromParent'
Expand Down Expand Up @@ -66,6 +68,8 @@ export const EditCreateCollectionForm = ({
const onEditMode = mode === 'edit'
const isEditingRootCollection =
onEditMode && CollectionHelper.isRootCollection(collection.hierarchy)
const canSelectStorageDriver = user.superuser
const storageDriverCollectionId = onEditMode ? collection.id : parentCollection.id

const {
metadataBlocksInfo,
Expand Down Expand Up @@ -102,6 +106,27 @@ export const EditCreateCollectionForm = ({
metadataBlockInfoRepository
})

const {
allowedStorageDrivers,
isLoading: isLoadingAllowedStorageDrivers,
error: allowedStorageDriversError
} = useGetCollectionAllowedStorageDrivers({
collectionIdOrAlias: storageDriverCollectionId,
collectionRepository,
enabled: canSelectStorageDriver
})

const {
storageDriver,
isLoading: isLoadingStorageDriver,
error: storageDriverError
} = useGetCollectionStorageDriver({
collectionIdOrAlias: storageDriverCollectionId,
collectionRepository,
enabled: canSelectStorageDriver,
getEffective: true
})

const baseInputLevels: FormattedCollectionInputLevels = useDeepCompareMemo(() => {
return CollectionFormHelper.defineBaseInputLevels(allMetadataBlocksInfoNormalized)
}, [allMetadataBlocksInfoNormalized])
Expand Down Expand Up @@ -149,13 +174,17 @@ export const EditCreateCollectionForm = ({
isLoadingMetadataBlocksInfo ||
isLoadingAllMetadataBlocksInfo ||
isLoadingCollectionFacets ||
isLoadingFacetableMetadataFields
isLoadingFacetableMetadataFields ||
isLoadingAllowedStorageDrivers ||
isLoadingStorageDriver

const dataLoadingErrors = [
metadataBlockInfoError,
allMetadataBlocksInfoError,
collectionFacetsError,
facetableMetadataFieldsError
facetableMetadataFieldsError,
allowedStorageDriversError,
storageDriverError
]

useEffect(() => {
Expand Down Expand Up @@ -204,6 +233,14 @@ export const EditCreateCollectionForm = ({
mode === 'edit' ? collection.isFacetRoot : undefined
)

const currentStorageDriverLabel = storageDriver?.label ?? storageDriver?.name
const defaultStorageDriver =
(currentStorageDriverLabel && allowedStorageDrivers[currentStorageDriverLabel] !== undefined
? currentStorageDriverLabel
: undefined) ??
Object.keys(allowedStorageDrivers)[0] ??
''

const formDefaultValues: CollectionFormData = {
hostCollection: isEditingRootCollection
? null
Expand All @@ -213,7 +250,7 @@ export const EditCreateCollectionForm = ({
type: onEditMode ? collection.type : '',
contacts: defaultContacts,
affiliation: onEditMode ? collection.affiliation ?? '' : user?.affiliation ?? '',
storage: 'S3',
storage: defaultStorageDriver,
description: onEditMode ? collection.description ?? '' : '',
[USE_FIELDS_FROM_PARENT]: useFieldsFromParentDefault,
[METADATA_BLOCKS_NAMES_GROUPER]: defaultBlocksNames,
Expand All @@ -231,6 +268,8 @@ export const EditCreateCollectionForm = ({
allFacetableMetadataFields={facetableMetadataFields}
defaultCollectionFacets={defaultCollectionFacets}
isEditingRootCollection={isEditingRootCollection}
canSelectStorageDriver={canSelectStorageDriver}
allowedStorageDrivers={allowedStorageDrivers}
/>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { EditCreateCollectionFormMode } from '../EditCreateCollectionForm'
import { RouteWithParams } from '@/sections/Route.enum'
import { useCollectionRepositories } from '@/shared/contexts/repositories/RepositoriesProvider'
import styles from './CollectionForm.module.scss'
import { AllowedStorageDrivers } from '@/collection/domain/models/AllowedStorageDrivers'

export interface CollectionFormProps {
mode: EditCreateCollectionFormMode
Expand All @@ -26,6 +27,8 @@ export interface CollectionFormProps {
allFacetableMetadataFields: MetadataField[]
defaultCollectionFacets: CollectionFormFacet[]
isEditingRootCollection: boolean
canSelectStorageDriver: boolean
allowedStorageDrivers: AllowedStorageDrivers
}

export const CollectionForm = ({
Expand All @@ -35,7 +38,9 @@ export const CollectionForm = ({
allMetadataBlocksInfo,
allFacetableMetadataFields,
defaultCollectionFacets,
isEditingRootCollection
isEditingRootCollection,
canSelectStorageDriver,
allowedStorageDrivers
}: CollectionFormProps) => {
const { collectionRepository } = useCollectionRepositories()
const formContainerRef = useRef<HTMLDivElement>(null)
Expand All @@ -53,7 +58,8 @@ export const CollectionForm = ({
collectionIdOrParentCollectionId,
collectionRepository,
onSubmittedCollectionError,
form.formState.dirtyFields
form.formState.dirtyFields,
canSelectStorageDriver
)

function onSubmittedCollectionError() {
Expand Down Expand Up @@ -92,7 +98,11 @@ export const CollectionForm = ({
onSubmit={form.handleSubmit(submitForm)}
noValidate={true}
data-testid="collection-form">
<TopFieldsSection isEditingRootCollection={isEditingRootCollection} />
<TopFieldsSection
isEditingRootCollection={isEditingRootCollection}
canSelectStorageDriver={canSelectStorageDriver}
allowedStorageDrivers={allowedStorageDrivers}
/>

<SeparationLine />

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { Controller, useFormContext } from 'react-hook-form'
import { useTranslation } from 'react-i18next'
import { Col, Form } from '@iqss/dataverse-design-system'
import { AllowedStorageDrivers } from '@/collection/domain/models/AllowedStorageDrivers'

interface StorageFieldProps {
allowedStorageDrivers: AllowedStorageDrivers
}

export const StorageField = ({ allowedStorageDrivers }: StorageFieldProps) => {
const { t } = useTranslation('shared', { keyPrefix: 'collectionForm' })
const { control } = useFormContext()
const storageDriverOptions = Object.entries(allowedStorageDrivers)

if (storageDriverOptions.length === 0) {
return null
}

return (
<Form.Group controlId="storage" as={Col} md={6}>
<Form.Group.Label message={t('fields.storage.description')}>
{t('fields.storage.label')}
</Form.Group.Label>
<Controller
name="storage"
control={control}
render={({ field: { onChange, ref, value }, fieldState: { invalid, error } }) => (
<Col>
<Form.Group.Select
onChange={onChange}
value={value as string}
isInvalid={invalid}
ref={ref}>
{storageDriverOptions.map(([driverLabel, displayName]) => (
<option value={driverLabel} key={driverLabel}>
{displayName}
</option>
))}
</Form.Group.Select>
<Form.Group.Feedback type="invalid">{error?.message}</Form.Group.Feedback>
</Col>
)}
/>
</Form.Group>
)
}
Loading
Loading