From 0b464741fde6f86a241d68b113d7a456006fff92 Mon Sep 17 00:00:00 2001 From: Charly B <47325354+EstherDarkish@users.noreply.github.com> Date: Mon, 22 Jan 2024 17:07:52 +0100 Subject: [PATCH 1/2] Fixes the contextual selection of elements. (#327) * Fixes the contextual selection of elements. Zimbra works like Google and others and as such, contextualMixPolicies.ZIMBRA is removed. --------- Signed-off-by: BOUTIER Charly --- src/components/directory-content.js | 118 ++++++++++-------- .../menus/content-contextual-menu.js | 1 + 2 files changed, 67 insertions(+), 52 deletions(-) diff --git a/src/components/directory-content.js b/src/components/directory-content.js index 36339a71b..6e91b74dd 100644 --- a/src/components/directory-content.js +++ b/src/components/directory-content.js @@ -282,6 +282,15 @@ const DirectoryContent = () => { }; /* User interactions */ + const contextualMixPolicies = useMemo( + () => ({ + BIG: 'GoogleMicrosoft', // if !selectedUuids.has(selected.Uuid) deselects selectedUuids + ALL: 'All', // union of activeElement.Uuid and selectedUuids (currently implemented) + }), + [] + ); + const contextualMixPolicy = contextualMixPolicies.ALL; + const onContextMenu = useCallback( (event) => { const element = currentChildren.find( @@ -295,6 +304,28 @@ const DirectoryContent = () => { if (element && element.uploading !== null) { if (element.type !== 'DIRECTORY') { setActiveElement(element); + + if (contextualMixPolicy === contextualMixPolicies.BIG) { + // If some elements were already selected and the active element is not in them, we deselect the already selected elements. + if ( + selectedUuids?.size && + element?.elementUuid && + !selectedUuids.has(element.elementUuid) + ) { + setSelectedUuids(new Set()); + } + } else { + // If some elements were already selected, we add the active element to the selected list if not already in it. + if ( + selectedUuids?.size && + element?.elementUuid && + !selectedUuids.has(element.elementUuid) + ) { + let updatedSelectedUuids = new Set(selectedUuids); + updatedSelectedUuids.add(element.elementUuid); + setSelectedUuids(updatedSelectedUuids); + } + } } setMousePosition({ mouseX: event.event.clientX + constants.HORIZONTAL_SHIFT, @@ -309,7 +340,14 @@ const DirectoryContent = () => { handleOpenDirectoryMenu(event); } }, - [currentChildren, dispatch, selectedDirectory] + [ + currentChildren, + dispatch, + selectedDirectory, + selectedUuids, + contextualMixPolicies, + contextualMixPolicy, + ] ); const abbreviationFromUserName = (name) => { @@ -728,60 +766,36 @@ const DirectoryContent = () => { setSelectedUuids(new Set()); }, [handleError, currentChildren, currentChildrenRef]); - const contextualMixPolicies = { - BIG: 'GoogleMicrosoft', // if !selectedUuids.has(selected.Uuid) deselects selectedUuids - ZIMBRA: 'Zimbra', // if !selectedUuids.has(selected.Uuid) just use activeElement - ALL: 'All', // union of activeElement.Uuid and selectedUuids (actually implemented) - }; - let contextualMixPolicy = contextualMixPolicies.ALL; - - const getSelectedChildren = (mayChange = false) => { - let acc = []; - let ctxtUuid = activeElement ? activeElement.elementUuid : null; - if (activeElement) { - acc.push( - Object.assign( - { - subtype: - childrenMetadata[activeElement.elementUuid] - ?.subtype, - }, - activeElement - ) - ); - } + const getSelectedChildren = () => { + let selectedChildren = []; + if (currentChildren?.length > 0) { + // Adds the previously selected elements + if (selectedUuids?.size) { + selectedChildren = currentChildren + .filter( + (child) => + selectedUuids.has(child.elementUuid) && + child.elementUuid !== activeElement?.elementUuid + ) + .map((child) => { + return { + subtype: + childrenMetadata[child.elementUuid]?.subtype, + ...child, + }; + }); + } - if (selectedUuids && currentChildren) { - if ( - contextualMixPolicy === contextualMixPolicies.ALL || - ctxtUuid === null || - selectedUuids.has(ctxtUuid) - ) { - acc = acc.concat( - currentChildren - .filter( - (child) => - selectedUuids.has(child.elementUuid) && - child.elementUuid !== activeElement?.elementUuid - ) - .map((child2) => { - return Object.assign( - { - subtype: - childrenMetadata[child2.elementUuid], - }, - child2 - ); - }) - ); - } else if ( - mayChange && - contextualMixPolicy === contextualMixPolicies.BIG - ) { - setSelectedUuids(null); + // Adds the active element + if (activeElement) { + selectedChildren.push({ + ...activeElement, + subtype: + childrenMetadata[activeElement.elementUuid]?.subtype, + }); } } - return [...new Set(acc)]; + return [...new Set(selectedChildren)]; }; const rows = useMemo( diff --git a/src/components/menus/content-contextual-menu.js b/src/components/menus/content-contextual-menu.js index dce8c73a0..d2d244d73 100644 --- a/src/components/menus/content-contextual-menu.js +++ b/src/components/menus/content-contextual-menu.js @@ -586,6 +586,7 @@ const ContentContextualMenu = (props) => { icon: , }); } + if (allowsDownloadCase()) { // is export allowed menuItems.push({ From ff2be1da4556e981eede7b1ebd6f01f3095a5878 Mon Sep 17 00:00:00 2001 From: dbraquart <107846716+dbraquart@users.noreply.github.com> Date: Tue, 23 Jan 2024 17:11:25 +0100 Subject: [PATCH 2/2] Hide some contextual menu items while creating case or study (#318) Signed-off-by: David BRAQUART --- src/components/directory-content.js | 14 ++++++++- .../menus/content-contextual-menu.js | 31 ++++++++++--------- src/components/toolbars/content-toolbar.js | 22 +++++++++---- src/translations/en.json | 2 +- src/translations/fr.json | 2 +- 5 files changed, 48 insertions(+), 23 deletions(-) diff --git a/src/components/directory-content.js b/src/components/directory-content.js index 6e91b74dd..b8b9e124e 100644 --- a/src/components/directory-content.js +++ b/src/components/directory-content.js @@ -303,7 +303,12 @@ const DirectoryContent = () => { if (element && element.uploading !== null) { if (element.type !== 'DIRECTORY') { - setActiveElement(element); + setActiveElement({ + hasMetadata: + childrenMetadata[event.rowData.elementUuid] !== + undefined, + ...element, + }); if (contextualMixPolicy === contextualMixPolicies.BIG) { // If some elements were already selected and the active element is not in them, we deselect the already selected elements. @@ -347,6 +352,7 @@ const DirectoryContent = () => { selectedUuids, contextualMixPolicies, contextualMixPolicy, + childrenMetadata, ] ); @@ -781,6 +787,9 @@ const DirectoryContent = () => { return { subtype: childrenMetadata[child.elementUuid]?.subtype, + hasMetadata: + childrenMetadata[child.elementUuid] !== + undefined, ...child, }; }); @@ -792,6 +801,9 @@ const DirectoryContent = () => { ...activeElement, subtype: childrenMetadata[activeElement.elementUuid]?.subtype, + hasMetadata: + childrenMetadata[activeElement.elementUuid] !== + undefined, }); } } diff --git a/src/components/menus/content-contextual-menu.js b/src/components/menus/content-contextual-menu.js index d2d244d73..b5ff2e54a 100644 --- a/src/components/menus/content-contextual-menu.js +++ b/src/components/menus/content-contextual-menu.js @@ -422,8 +422,8 @@ const ContentContextualMenu = (props) => { false ); - const isNotUploadingElement = useCallback(() => { - return selectedElements.every((el) => !el.uploading); + const noCreationInProgress = useCallback(() => { + return selectedElements.every((el) => el.hasMetadata); }, [selectedElements]); // Allowance @@ -434,14 +434,14 @@ const ContentContextualMenu = (props) => { }, [selectedElements, userId]); const allowsDelete = useCallback(() => { - return isUserAllowed() && isNotUploadingElement(); - }, [isUserAllowed, isNotUploadingElement]); + return isUserAllowed() && noCreationInProgress(); + }, [isUserAllowed, noCreationInProgress]); const allowsRename = useCallback(() => { return ( selectedElements.length === 1 && isUserAllowed() && - !selectedElements[0].uploading + selectedElements[0].hasMetadata ); }, [isUserAllowed, selectedElements]); @@ -449,21 +449,22 @@ const ContentContextualMenu = (props) => { return ( selectedElements.every( (element) => - element.type !== ElementType.DIRECTORY && !element.uploading + element.type !== ElementType.DIRECTORY && + element.hasMetadata ) && isUserAllowed() ); }, [isUserAllowed, selectedElements]); const allowsDuplicate = useCallback(() => { return ( + selectedElements[0].hasMetadata && selectedElements.length === 1 && (selectedElements[0].type === ElementType.CASE || selectedElements[0].type === ElementType.STUDY || selectedElements[0].type === ElementType.CONTINGENCY_LIST || selectedElements[0].type === ElementType.FILTER || selectedElements[0].type === - ElementType.VOLTAGE_INIT_PARAMETERS) && - !selectedElements[0].uploading + ElementType.VOLTAGE_INIT_PARAMETERS) ); }, [selectedElements]); @@ -471,7 +472,7 @@ const ContentContextualMenu = (props) => { return ( selectedElements.length === 1 && selectedElements[0].type === ElementType.CASE && - !selectedElements[0].uploading + selectedElements[0].hasMetadata ); }, [selectedElements]); @@ -496,10 +497,12 @@ const ContentContextualMenu = (props) => { const allowsDownloadCase = useCallback(() => { //if selectedElements contains at least one case - return selectedElements.some( - (element) => element.type === ElementType.CASE + return ( + selectedElements.some( + (element) => element.type === ElementType.CASE + ) && noCreationInProgress() ); - }, [selectedElements]); + }, [selectedElements, noCreationInProgress]); const handleDownloadCases = useCallback(async () => { const casesUuids = selectedElements @@ -613,9 +616,9 @@ const ContentContextualMenu = (props) => { if (menuItems.length === 0) { menuItems.push({ - messageDescriptorId: isNotUploadingElement() + messageDescriptorId: noCreationInProgress() ? 'notElementCreator' - : 'uploadingElement', + : 'elementCreationInProgress', icon: , disabled: true, }); diff --git a/src/components/toolbars/content-toolbar.js b/src/components/toolbars/content-toolbar.js index 44eba4fc8..5a19ce3d4 100644 --- a/src/components/toolbars/content-toolbar.js +++ b/src/components/toolbars/content-toolbar.js @@ -131,22 +131,32 @@ const ContentToolbar = (props) => { [selectedElements, userId] ); - const allowsDelete = useMemo(() => isUserAllowed, [isUserAllowed]); + const noCreationInProgress = useMemo( + () => selectedElements.every((el) => el.hasMetadata), + [selectedElements] + ); + + const allowsDelete = useMemo( + () => isUserAllowed && noCreationInProgress, + [isUserAllowed, noCreationInProgress] + ); const allowsMove = useMemo( () => selectedElements.every( (element) => element.type !== ElementType.DIRECTORY - ) && isUserAllowed, - [isUserAllowed, selectedElements] + ) && + isUserAllowed && + noCreationInProgress, + [isUserAllowed, selectedElements, noCreationInProgress] ); const allowsDownloadCases = useMemo( () => - selectedElements.every( + selectedElements.some( (element) => element.type === ElementType.CASE - ), - [selectedElements] + ) && noCreationInProgress, + [selectedElements, noCreationInProgress] ); const items = useMemo( diff --git a/src/translations/en.json b/src/translations/en.json index 8c7e1e0a0..e59fe6f2d 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -212,7 +212,7 @@ "moveElementNotFoundError": "The element or the targeted folder was not found", "moveElementNotAllowedError": "You cannot move this element to the targeted folder. Unauthorized action", "notElementCreator": "You are not the element's creator", - "uploadingElement": "Upload in progress: no operation permitted", + "elementCreationInProgress": "Creation in progress: no operation permitted", "serverConnectionFailed": "Failed to connect to server. Please retry later.", "invalidFormatOrName": "Imported file name or format invalid", "parameterLoadingProblem": "problem of loading parameters", diff --git a/src/translations/fr.json b/src/translations/fr.json index e11e0d922..56c7878d8 100644 --- a/src/translations/fr.json +++ b/src/translations/fr.json @@ -212,7 +212,7 @@ "moveElementNotFoundError": "L'élément ou le dossier cible n'a pas été trouvé", "moveElementNotAllowedError": "Vous ne pouvez pas déplacer cet élément dans le dossier cible. Action non autorisée", "notElementCreator": "Vous n'êtes pas le créateur de l'élément", - "uploadingElement": "Téléversement en cours : pas d'opération autorisée", + "elementCreationInProgress": "Création en cours : pas d'opération autorisée", "serverConnectionFailed": "Échec de connexion avec le serveur. Veuillez réessayer ultérieurement", "invalidFormatOrName": "Format ou nom du fichier importé non valide", "parameterLoadingProblem": "Problème de chargement des paramètres",