From dbe71f519c69a1b7a8b674438e949760a4556987 Mon Sep 17 00:00:00 2001 From: basseche Date: Thu, 26 Dec 2024 10:36:36 +0100 Subject: [PATCH 1/4] Case import : compute base name from case-server instead of front computation --- .../dialogs/commons/prefilled-name-input.tsx | 9 ++++++--- src/components/dialogs/commons/upload-new-case.tsx | 10 +--------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/components/dialogs/commons/prefilled-name-input.tsx b/src/components/dialogs/commons/prefilled-name-input.tsx index c7a17a6c5..3768eaa83 100644 --- a/src/components/dialogs/commons/prefilled-name-input.tsx +++ b/src/components/dialogs/commons/prefilled-name-input.tsx @@ -7,7 +7,7 @@ import { useEffect, useState } from 'react'; import { useFormContext } from 'react-hook-form'; -import { ElementType, FieldConstants, UniqueNameInput } from '@gridsuite/commons-ui'; +import { ElementType, FieldConstants, UniqueNameInput, useSnackMessage } from '@gridsuite/commons-ui'; import { useSelector } from 'react-redux'; import { elementExists, getBaseName } from '../../../utils/rest-api'; import { AppState } from '../../../redux/types'; @@ -31,6 +31,7 @@ export default function PrefilledNameInput({ label, name, elementType }: Readonl } = useFormContext(); const [modifiedByUser, setModifiedByUser] = useState(false); + const { snackError } = useSnackMessage(); const caseFile = watch(FieldConstants.CASE_FILE) as File; const caseFileErrorMessage = errors.caseFile?.message; @@ -52,11 +53,13 @@ export default function PrefilledNameInput({ label, name, elementType }: Readonl }); }) .catch((error) => { - console.error('Error fetching base name:', error); + snackError({ + messageTxt: error.message, + }); }); } } - }, [caseFile, modifiedByUser, apiCallErrorMessage, caseFileErrorMessage, setValue, clearErrors, name]); + }, [caseFile, modifiedByUser, apiCallErrorMessage, caseFileErrorMessage, setValue, clearErrors, name, snackError]); return ( Date: Mon, 30 Dec 2024 13:49:37 +0100 Subject: [PATCH 2/4] fix validation --- .../dialogs/commons/prefilled-name-input.tsx | 16 ++++++++++++++-- .../dialogs/commons/upload-new-case.tsx | 7 ------- .../create-case-dialog/create-case-dialog.tsx | 2 +- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/components/dialogs/commons/prefilled-name-input.tsx b/src/components/dialogs/commons/prefilled-name-input.tsx index 3768eaa83..e0439ff9a 100644 --- a/src/components/dialogs/commons/prefilled-name-input.tsx +++ b/src/components/dialogs/commons/prefilled-name-input.tsx @@ -25,6 +25,7 @@ export interface PrefilledNameInputProps { export default function PrefilledNameInput({ label, name, elementType }: Readonly) { const { setValue, + getValues, clearErrors, watch, formState: { errors }, @@ -43,8 +44,9 @@ export default function PrefilledNameInput({ label, name, elementType }: Readonl // we replace the name only if some conditions are respected if (caseFile && !modifiedByUser && !apiCallErrorMessage && !caseFileErrorMessage) { const { name: caseName } = caseFile; + const currentCaseName = getValues(name); - if (caseName) { + if (caseName && caseName !== currentCaseName) { clearErrors(name); getBaseName(caseName) .then((response) => { @@ -59,7 +61,17 @@ export default function PrefilledNameInput({ label, name, elementType }: Readonl }); } } - }, [caseFile, modifiedByUser, apiCallErrorMessage, caseFileErrorMessage, setValue, clearErrors, name, snackError]); + }, [ + caseFile, + modifiedByUser, + apiCallErrorMessage, + caseFileErrorMessage, + setValue, + getValues, + clearErrors, + name, + snackError, + ]); return ( { setCaseFileLoading(false); }); - } else { - const caseName = getValues(FieldConstants.CASE_NAME); - if (currentCaseFileName && caseName !== currentCaseFileName) { - clearErrors(FieldConstants.CASE_NAME); - } } } else { setError(FieldConstants.CASE_FILE, { diff --git a/src/components/dialogs/create-case-dialog/create-case-dialog.tsx b/src/components/dialogs/create-case-dialog/create-case-dialog.tsx index 08fb21ffd..4360b2991 100644 --- a/src/components/dialogs/create-case-dialog/create-case-dialog.tsx +++ b/src/components/dialogs/create-case-dialog/create-case-dialog.tsx @@ -126,7 +126,7 @@ export default function CreateCaseDialog({ onClose, open }: Readonly - + ); } From 6b0c1fdbde2da10c4bae509ba9cf40dadb5e9306 Mon Sep 17 00:00:00 2001 From: Rehili Ghazwa Date: Fri, 3 Jan 2025 14:40:24 +0100 Subject: [PATCH 3/4] correction for getBaseName --- .../dialogs/commons/prefilled-name-input.tsx | 52 ++----------------- .../dialogs/commons/upload-new-case.tsx | 28 ++++++++-- .../create-case-dialog/create-case-dialog.tsx | 2 +- 3 files changed, 27 insertions(+), 55 deletions(-) diff --git a/src/components/dialogs/commons/prefilled-name-input.tsx b/src/components/dialogs/commons/prefilled-name-input.tsx index e0439ff9a..4978f9ecf 100644 --- a/src/components/dialogs/commons/prefilled-name-input.tsx +++ b/src/components/dialogs/commons/prefilled-name-input.tsx @@ -5,11 +5,10 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { useEffect, useState } from 'react'; import { useFormContext } from 'react-hook-form'; -import { ElementType, FieldConstants, UniqueNameInput, useSnackMessage } from '@gridsuite/commons-ui'; +import { ElementType, FieldConstants, UniqueNameInput } from '@gridsuite/commons-ui'; import { useSelector } from 'react-redux'; -import { elementExists, getBaseName } from '../../../utils/rest-api'; +import { elementExists } from '../../../utils/rest-api'; import { AppState } from '../../../redux/types'; export interface PrefilledNameInputProps { @@ -23,56 +22,12 @@ export interface PrefilledNameInputProps { * Used for CreateCaseDialog and CreateStudyDialog */ export default function PrefilledNameInput({ label, name, elementType }: Readonly) { - const { - setValue, - getValues, - clearErrors, - watch, - formState: { errors }, - } = useFormContext(); - - const [modifiedByUser, setModifiedByUser] = useState(false); - const { snackError } = useSnackMessage(); + const { watch } = useFormContext(); const caseFile = watch(FieldConstants.CASE_FILE) as File; - const caseFileErrorMessage = errors.caseFile?.message; - const apiCallErrorMessage = errors.root?.apiCall?.message; const activeDirectory = useSelector((state: AppState) => state.activeDirectory); - useEffect(() => { - // we replace the name only if some conditions are respected - if (caseFile && !modifiedByUser && !apiCallErrorMessage && !caseFileErrorMessage) { - const { name: caseName } = caseFile; - const currentCaseName = getValues(name); - - if (caseName && caseName !== currentCaseName) { - clearErrors(name); - getBaseName(caseName) - .then((response) => { - setValue(name, response, { - shouldDirty: true, - }); - }) - .catch((error) => { - snackError({ - messageTxt: error.message, - }); - }); - } - } - }, [ - caseFile, - modifiedByUser, - apiCallErrorMessage, - caseFileErrorMessage, - setValue, - getValues, - clearErrors, - name, - snackError, - ]); - return ( setModifiedByUser(true)} /> ); } diff --git a/src/components/dialogs/commons/upload-new-case.tsx b/src/components/dialogs/commons/upload-new-case.tsx index f03448436..59a35d6c4 100644 --- a/src/components/dialogs/commons/upload-new-case.tsx +++ b/src/components/dialogs/commons/upload-new-case.tsx @@ -9,9 +9,9 @@ import { ChangeEvent, useMemo, useState } from 'react'; import { FormattedMessage, useIntl } from 'react-intl'; import { Button, CircularProgress, Grid, Input } from '@mui/material'; import { useController, useFormContext } from 'react-hook-form'; -import { FieldConstants } from '@gridsuite/commons-ui'; +import { FieldConstants, useSnackMessage } from '@gridsuite/commons-ui'; import { UUID } from 'crypto'; -import { createCaseWithoutDirectoryElementCreation, deleteCase } from '../../../utils/rest-api'; +import { createCaseWithoutDirectoryElementCreation, deleteCase, getBaseName } from '../../../utils/rest-api'; export interface UploadNewCaseProps { isNewStudyCreation?: boolean; @@ -28,7 +28,7 @@ export default function UploadNewCase({ handleApiCallError, }: Readonly) { const intl = useIntl(); - + const { snackError } = useSnackMessage(); const [caseFileLoading, setCaseFileLoading] = useState(false); const { @@ -43,7 +43,7 @@ export default function UploadNewCase({ name: FieldConstants.CASE_UUID, }); - const { clearErrors, setError, getValues } = useFormContext(); + const { clearErrors, setError, getValues, setValue } = useFormContext(); const caseFile = value as File; const { name: caseFileName } = caseFile || {}; @@ -58,6 +58,24 @@ export default function UploadNewCase({ return ; }, [caseFileLoading, caseFileName]); + const fetchBaseName = (currentFile: any) => { + const { name: currentCaseFileName } = currentFile; + const name = isNewStudyCreation ? FieldConstants.STUDY_NAME : FieldConstants.CASE_NAME; + if (currentCaseFileName) { + getBaseName(currentCaseFileName) + .then((response) => { + setValue(name, response, { + shouldValidate: true, + }); + }) + .catch((error) => { + snackError({ + messageTxt: error.message, + }); + }); + } + }; + const onChange = (event: ChangeEvent) => { event.preventDefault(); @@ -71,7 +89,7 @@ export default function UploadNewCase({ if (currentFile.size <= MAX_FILE_SIZE_IN_BYTES) { onValueChange(currentFile); - + fetchBaseName(currentFile); if (isNewStudyCreation) { // Create new case setCaseFileLoading(true); diff --git a/src/components/dialogs/create-case-dialog/create-case-dialog.tsx b/src/components/dialogs/create-case-dialog/create-case-dialog.tsx index 4360b2991..08fb21ffd 100644 --- a/src/components/dialogs/create-case-dialog/create-case-dialog.tsx +++ b/src/components/dialogs/create-case-dialog/create-case-dialog.tsx @@ -126,7 +126,7 @@ export default function CreateCaseDialog({ onClose, open }: Readonly - + ); } From 285989f916cfbe0a2f323ea21a681fd4d2786358 Mon Sep 17 00:00:00 2001 From: Rehili Ghazwa Date: Wed, 8 Jan 2025 10:47:31 +0100 Subject: [PATCH 4/4] implement user modified option --- .../dialogs/commons/prefilled-name-input.tsx | 41 ------------------- .../dialogs/commons/upload-new-case.tsx | 4 +- .../create-case-dialog/create-case-dialog.tsx | 16 ++++++-- .../create-study-dialog.tsx | 17 +++++--- 4 files changed, 26 insertions(+), 52 deletions(-) delete mode 100644 src/components/dialogs/commons/prefilled-name-input.tsx diff --git a/src/components/dialogs/commons/prefilled-name-input.tsx b/src/components/dialogs/commons/prefilled-name-input.tsx deleted file mode 100644 index 4978f9ecf..000000000 --- a/src/components/dialogs/commons/prefilled-name-input.tsx +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Copyright (c) 2023, RTE (http://www.rte-france.com) - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -import { useFormContext } from 'react-hook-form'; -import { ElementType, FieldConstants, UniqueNameInput } from '@gridsuite/commons-ui'; -import { useSelector } from 'react-redux'; -import { elementExists } from '../../../utils/rest-api'; -import { AppState } from '../../../redux/types'; - -export interface PrefilledNameInputProps { - label: string; - name: string; - elementType: ElementType; -} - -/** - * Input component that automatically fill the field when a case is uploaded - * Used for CreateCaseDialog and CreateStudyDialog - */ -export default function PrefilledNameInput({ label, name, elementType }: Readonly) { - const { watch } = useFormContext(); - - const caseFile = watch(FieldConstants.CASE_FILE) as File; - - const activeDirectory = useSelector((state: AppState) => state.activeDirectory); - - return ( - - ); -} diff --git a/src/components/dialogs/commons/upload-new-case.tsx b/src/components/dialogs/commons/upload-new-case.tsx index 59a35d6c4..71ba51ebb 100644 --- a/src/components/dialogs/commons/upload-new-case.tsx +++ b/src/components/dialogs/commons/upload-new-case.tsx @@ -14,6 +14,7 @@ import { UUID } from 'crypto'; import { createCaseWithoutDirectoryElementCreation, deleteCase, getBaseName } from '../../../utils/rest-api'; export interface UploadNewCaseProps { + modifiedByUser?: boolean; isNewStudyCreation?: boolean; getCurrentCaseImportParams?: (uuid: UUID) => void; handleApiCallError?: ErrorCallback; @@ -23,6 +24,7 @@ const MAX_FILE_SIZE_IN_MO = 100; const MAX_FILE_SIZE_IN_BYTES = MAX_FILE_SIZE_IN_MO * 1024 * 1024; export default function UploadNewCase({ + modifiedByUser = false, isNewStudyCreation = false, getCurrentCaseImportParams, handleApiCallError, @@ -61,7 +63,7 @@ export default function UploadNewCase({ const fetchBaseName = (currentFile: any) => { const { name: currentCaseFileName } = currentFile; const name = isNewStudyCreation ? FieldConstants.STUDY_NAME : FieldConstants.CASE_NAME; - if (currentCaseFileName) { + if (currentCaseFileName && !modifiedByUser) { getBaseName(currentCaseFileName) .then((response) => { setValue(name, response, { diff --git a/src/components/dialogs/create-case-dialog/create-case-dialog.tsx b/src/components/dialogs/create-case-dialog/create-case-dialog.tsx index 08fb21ffd..4dea31998 100644 --- a/src/components/dialogs/create-case-dialog/create-case-dialog.tsx +++ b/src/components/dialogs/create-case-dialog/create-case-dialog.tsx @@ -18,10 +18,12 @@ import { FieldErrorAlert, isObjectEmpty, keyGenerator, + UniqueNameInput, useConfidentialityWarning, useSnackMessage, } from '@gridsuite/commons-ui'; -import { createCase } from '../../../utils/rest-api'; +import { useState } from 'react'; +import { createCase, elementExists } from '../../../utils/rest-api'; import { HTTP_UNPROCESSABLE_ENTITY_STATUS } from '../../../utils/UIconstants'; import { addUploadingElement, removeUploadingElement } from '../../../redux/actions'; import UploadNewCase from '../commons/upload-new-case'; @@ -29,7 +31,6 @@ import { createCaseDialogFormValidationSchema, getCreateCaseDialogFormValidationDefaultValues, } from './create-case-dialog-utils'; -import PrefilledNameInput from '../commons/prefilled-name-input'; import { handleMaxElementsExceededError } from '../../utils/rest-errors'; import { AppDispatch } from '../../../redux/store'; import { AppState, UploadingElement } from '../../../redux/types'; @@ -57,12 +58,14 @@ export default function CreateCaseDialog({ onClose, open }: Readonly state.activeDirectory); const userId = useSelector((state: AppState) => state.user?.profile.sub); + const [modifiedByUser, setModifiedByUser] = useState(false); const handleCreateNewCase = ({ caseName, description, caseFile }: IFormData): void => { const uploadingCase: UploadingElement = { @@ -100,6 +103,7 @@ export default function CreateCaseDialog({ onClose, open }: Readonly - setModifiedByUser(true)} /> @@ -126,7 +134,7 @@ export default function CreateCaseDialog({ onClose, open }: Readonly - + ); } diff --git a/src/components/dialogs/create-study-dialog/create-study-dialog.tsx b/src/components/dialogs/create-study-dialog/create-study-dialog.tsx index 0fcead6b3..083210092 100644 --- a/src/components/dialogs/create-study-dialog/create-study-dialog.tsx +++ b/src/components/dialogs/create-study-dialog/create-study-dialog.tsx @@ -7,7 +7,7 @@ import { useForm } from 'react-hook-form'; import { Grid } from '@mui/material'; import { useIntl } from 'react-intl'; -import { useCallback, useEffect } from 'react'; +import { useCallback, useEffect, useState } from 'react'; import { CustomMuiDialog, DescriptionField, @@ -20,6 +20,7 @@ import { keyGenerator, ModifyElementSelection, Parameter, + UniqueNameInput, useConfidentialityWarning, useSnackMessage, } from '@gridsuite/commons-ui'; @@ -27,7 +28,7 @@ import { useDispatch, useSelector } from 'react-redux'; import { yupResolver } from '@hookform/resolvers/yup/dist/yup'; import { UUID } from 'crypto'; import UploadNewCase from '../commons/upload-new-case'; -import { createStudy, deleteCase, getCaseImportParameters } from '../../../utils/rest-api'; +import { createStudy, deleteCase, elementExists, getCaseImportParameters } from '../../../utils/rest-api'; import { HTTP_CONNECTION_FAILED_MESSAGE, HTTP_UNPROCESSABLE_ENTITY_STATUS } from '../../../utils/UIconstants'; import ImportParametersSection from './importParametersSection'; import { addUploadingElement, removeUploadingElement, setActiveDirectory } from '../../../redux/actions'; @@ -36,7 +37,6 @@ import { CreateStudyDialogFormValues, getCreateStudyDialogFormDefaultValues, } from './create-study-dialog-utils'; -import PrefilledNameInput from '../commons/prefilled-name-input'; import { handleMaxElementsExceededError } from '../../utils/rest-errors'; import { AppState, UploadingElement } from '../../../redux/types'; @@ -77,7 +77,7 @@ export default function CreateStudyDialog({ open, onClose, providedExistingCase const activeDirectory = useSelector((state: AppState) => state.activeDirectory); const selectedDirectory = useSelector((state: AppState) => state.selectedDirectory); const userId = useSelector((state: AppState) => state.user?.profile.sub); - + const [modifiedByUser, setModifiedByUser] = useState(false); const { elementUuid, elementName } = providedExistingCase || {}; const createStudyFormMethods = useForm({ @@ -237,7 +237,7 @@ export default function CreateStudyDialog({ open, onClose, providedExistingCase getCurrentCaseImportParams(providedExistingCase.elementUuid); } }, [getCurrentCaseImportParams, providedExistingCase, setValue]); - + const caseFileStudy = getValues(FieldConstants.CASE_FILE); return ( - setModifiedByUser(true)} /> @@ -272,6 +276,7 @@ export default function CreateStudyDialog({ open, onClose, providedExistingCase /> ) : (