From 577e79c4b90714f59fe4241aa1df85cece4debb9 Mon Sep 17 00:00:00 2001 From: Cheng Shi Date: Fri, 6 Feb 2026 16:27:11 -0500 Subject: [PATCH 1/4] feat: upload limit intergation --- package-lock.json | 8 +- package.json | 2 +- public/locales/en/shared.json | 3 + public/locales/es/shared.json | 3 + .../domain/models/DatasetUploadLimits.ts | 4 + .../domain/useCases/getDatasetUploadLimits.ts | 8 ++ .../file-upload-input/FileUploadInput.tsx | 25 +++++++ .../file-upload-input/useUploadLimit.ts | 65 +++++++++++++++++ .../FileUploadInputUploadLimits.spec.tsx | 73 +++++++++++++++++++ .../file-uploader/useUploadLimit.spec.tsx | 43 +++++++++++ 10 files changed, 229 insertions(+), 5 deletions(-) create mode 100644 src/dataset/domain/models/DatasetUploadLimits.ts create mode 100644 src/dataset/domain/useCases/getDatasetUploadLimits.ts create mode 100644 src/sections/shared/file-uploader/file-upload-input/useUploadLimit.ts create mode 100644 tests/component/sections/shared/file-uploader/FileUploadInputUploadLimits.spec.tsx create mode 100644 tests/component/sections/shared/file-uploader/useUploadLimit.spec.tsx diff --git a/package-lock.json b/package-lock.json index cf249ad1d..f63cd72ab 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,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.85", + "@iqss/dataverse-client-javascript": "v2.1.0-pr421.6d795bb", "@iqss/dataverse-design-system": "*", "@istanbuljs/nyc-config-typescript": "1.0.2", "@tanstack/react-table": "8.9.2", @@ -1954,9 +1954,9 @@ }, "node_modules/@iqss/dataverse-client-javascript": { "name": "@IQSS/dataverse-client-javascript", - "version": "2.0.0-alpha.85", - "resolved": "https://npm.pkg.github.com/download/@IQSS/dataverse-client-javascript/2.0.0-alpha.85/9f7d8be5c1fbe022c11fcc6d956bbf1cc4821776", - "integrity": "sha512-2aEA0MdkhFjugxImJ3a334jlVbwmNMDVsFXnwPutbbkqn89UMXClMxADkqlmLQ3/4dOMtOrdVDitxYsYmYZ6RQ==", + "version": "2.1.0-pr421.6d795bb", + "resolved": "https://npm.pkg.github.com/download/@IQSS/dataverse-client-javascript/2.1.0-pr421.6d795bb/f4fcb31c1f3f1fe4fd84c3f81bdab8d00555d83a", + "integrity": "sha512-EGWgECeBuemUswYnxgJiZtVw+XVYC/V6R/mC4qtvFMsFwqBmvX84JBqgoEVUnLLJ1PHPd+oYEbmUgJt0Vqc0hg==", "license": "MIT", "dependencies": { "@types/node": "^18.15.11", diff --git a/package.json b/package.json index 3b8b27edf..4a647ea32 100644 --- a/package.json +++ b/package.json @@ -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.0.0-alpha.85", + "@iqss/dataverse-client-javascript": "v2.1.0-pr421.6d795bb", "@iqss/dataverse-design-system": "*", "@istanbuljs/nyc-config-typescript": "1.0.2", "@tanstack/react-table": "8.9.2", diff --git a/public/locales/en/shared.json b/public/locales/en/shared.json index d4dbc4e26..e00b67b0b 100644 --- a/public/locales/en/shared.json +++ b/public/locales/en/shared.json @@ -220,6 +220,9 @@ "selectFileMultiple": "Select files to add", "dragDropSingle": "Drag and drop file here.", "dragDropMultiple": "Drag and drop files and/or directories here.", + "uploadWidgetHelp": "Select files or drag and drop into the upload widget. Maximum of {{maxFilesPerUpload}} files per upload.", + "uploadWidgetMaxFilesHelp": "Maximum of {{maxFilesAvailableToUpload}} files available to upload.", + "uploadWidgetStorageQuotaHelp": "Storage quota: {{storageQuotaRemaining}} remaining.", "cancelUpload": "Cancel upload", "uploadFailed": "There was an error uploading this file.", "loadingConfiguration": "Loading configuration", diff --git a/public/locales/es/shared.json b/public/locales/es/shared.json index a3010a550..d22e10dcd 100644 --- a/public/locales/es/shared.json +++ b/public/locales/es/shared.json @@ -220,6 +220,9 @@ "selectFileMultiple": "Seleccionar ficheros para agregar", "dragDropSingle": "Arrastra y suelta el fichero aquí.", "dragDropMultiple": "Arrastra y suelta ficheros y/o directorios aquí.", + "uploadWidgetHelp": "Selecciona ficheros o arrástralos y suéltalos en el widget de carga. Máximo de {{maxFilesPerUpload}} ficheros por carga.", + "uploadWidgetMaxFilesHelp": "Máximo de {{maxFilesAvailableToUpload}} ficheros disponibles para cargar.", + "uploadWidgetStorageQuotaHelp": "Cuota de almacenamiento: {{storageQuotaRemaining}} restantes.", "cancelUpload": "Cancelar carga", "uploadFailed": "Ocurrió un error al cargar este fichero.", "loadingConfiguration": "Cargando configuración", diff --git a/src/dataset/domain/models/DatasetUploadLimits.ts b/src/dataset/domain/models/DatasetUploadLimits.ts new file mode 100644 index 000000000..6dbf22205 --- /dev/null +++ b/src/dataset/domain/models/DatasetUploadLimits.ts @@ -0,0 +1,4 @@ +export interface DatasetUploadLimits { + numberOfFilesRemaining?: number + storageQuotaRemaining?: number +} diff --git a/src/dataset/domain/useCases/getDatasetUploadLimits.ts b/src/dataset/domain/useCases/getDatasetUploadLimits.ts new file mode 100644 index 000000000..e28bbebe4 --- /dev/null +++ b/src/dataset/domain/useCases/getDatasetUploadLimits.ts @@ -0,0 +1,8 @@ +import { getDatasetUploadLimits as jsGetDatasetUploadLimits } from '@iqss/dataverse-client-javascript' +import { DatasetUploadLimits } from '../models/DatasetUploadLimits' + +export async function getDatasetUploadLimits( + datasetId: string | number +): Promise { + return jsGetDatasetUploadLimits.execute(datasetId) +} diff --git a/src/sections/shared/file-uploader/file-upload-input/FileUploadInput.tsx b/src/sections/shared/file-uploader/file-upload-input/FileUploadInput.tsx index e24995e0c..b1bf0c072 100644 --- a/src/sections/shared/file-uploader/file-upload-input/FileUploadInput.tsx +++ b/src/sections/shared/file-uploader/file-upload-input/FileUploadInput.tsx @@ -14,6 +14,7 @@ import { OperationType } from '../FileUploader' import { FileUploaderHelper } from '../FileUploaderHelper' import { SwalModal } from '../../swal-modal/SwalModal' import styles from './FileUploadInput.module.scss' +import { useUploadLimit } from './useUploadLimit' type FileUploadInputProps = { fileRepository: FileRepository @@ -23,6 +24,8 @@ type FileUploadInputProps = { const limit = 6 const semaphore = new Semaphore(limit) +const maxFilesPerUpload = 1000 + const FileUploadInput = ({ fileRepository, datasetPersistentId }: FileUploadInputProps) => { const { fileUploaderState, @@ -44,6 +47,7 @@ const FileUploadInput = ({ fileRepository, datasetPersistentId }: FileUploadInpu const inputRef = useRef(null) const [isDragging, setIsDragging] = useState(false) + const { uploadLimit } = useUploadLimit(datasetPersistentId) const totalFiles = Object.keys(fileUploaderState.files).length @@ -267,6 +271,27 @@ const FileUploadInput = ({ fileRepository, datasetPersistentId }: FileUploadInpu {t('fileUploader.accordionTitle')} +

+ {t('fileUploader.uploadWidgetHelp', { + maxFilesPerUpload: maxFilesPerUpload.toLocaleString() + })} + {uploadLimit.maxFilesAvailableToUploadFormatted && ( + <> + {' '} + {t('fileUploader.uploadWidgetMaxFilesHelp', { + maxFilesAvailableToUpload: uploadLimit.maxFilesAvailableToUploadFormatted + })} + + )} + {uploadLimit.storageQuotaRemainingFormatted && ( + <> + {' '} + {t('fileUploader.uploadWidgetStorageQuotaHelp', { + storageQuotaRemaining: uploadLimit.storageQuotaRemainingFormatted + })} + + )} +