Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you update to 2.2.0-alpha.9 as our latest js-dataverse alpha ver.?

"@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 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>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,20 @@ import { collectionTypeOptions } from '@/collection/domain/useCases/DTOs/Collect
import { ContactsField } from './ContactsField'
import { IdentifierField } from './IdentifierField'
import { DescriptionField } from './DescriptionField'
import { StorageField } from './StorageField'
import { AllowedStorageDrivers } from '@/collection/domain/models/AllowedStorageDrivers'

interface TopFieldsSectionProps {
isEditingRootCollection: boolean
canSelectStorageDriver: boolean
allowedStorageDrivers: AllowedStorageDrivers
}

export const TopFieldsSection = ({ isEditingRootCollection }: TopFieldsSectionProps) => {
export const TopFieldsSection = ({
isEditingRootCollection,
canSelectStorageDriver,
allowedStorageDrivers
}: TopFieldsSectionProps) => {
const { t } = useTranslation('shared', { keyPrefix: 'collectionForm' })
const { control } = useFormContext()

Expand Down Expand Up @@ -152,34 +160,7 @@ export const TopFieldsSection = ({ isEditingRootCollection }: TopFieldsSectionPr
<Row>
<IdentifierField rules={aliasRules} />

{/* 👇 To be defined, at the moment the SPA only supports file uploading through direct upload (S3), so we are disabling the storage selector */}
{/* <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}
disabled>
<option value="">Select...</option>
{Object.values(collectionStorageOptions).map((type) => (
<option value={type} key={type}>
{type}
</option>
))}
</Form.Group.Select>
<Form.Group.Feedback type="invalid">{error?.message}</Form.Group.Feedback>
</Col>
)}
/>
</Form.Group> */}
{canSelectStorageDriver && <StorageField allowedStorageDrivers={allowedStorageDrivers} />}
</Row>

{/* Category (type) & Email (contacts) & Description */}
Expand Down
Loading
Loading