From f14c83c78b1486caba84f36cd713f6abc78b05dd Mon Sep 17 00:00:00 2001 From: shuhaib-aot Date: Wed, 15 Jan 2025 12:12:47 +0530 Subject: [PATCH 1/4] Feature: changed multi select customcompoenant in mfa --- .../CustomComponents/MultiSelect.js | 120 ------------------ .../src/components/Form/EditForm/FormEdit.js | 8 +- .../components/Form/EditForm/FormSettings.js | 71 ++++++----- forms-flow-web/src/helper/helper.js | 21 ++- 4 files changed, 65 insertions(+), 155 deletions(-) delete mode 100644 forms-flow-web/src/components/CustomComponents/MultiSelect.js diff --git a/forms-flow-web/src/components/CustomComponents/MultiSelect.js b/forms-flow-web/src/components/CustomComponents/MultiSelect.js deleted file mode 100644 index 0ef401645..000000000 --- a/forms-flow-web/src/components/CustomComponents/MultiSelect.js +++ /dev/null @@ -1,120 +0,0 @@ -import React, { useState, useRef, useEffect } from "react"; -import { useSelector } from "react-redux"; -import { ListGroup } from "react-bootstrap"; -import { CustomPill,DeleteIcon } from "@formsflow/components"; -import PropTypes from 'prop-types'; -import { HelperServices, StyleServices } from "@formsflow/service"; - -const RoleSelector = ({ - allRoles = [], - selectedRoles = [], - setSelectedRoles, - openByDefault = false, -}) => { - const primaryColor = StyleServices.getCSSVariable('primary'); - const [roleInput, setRoleInput] = useState(""); - const [filteredRoles, setFilteredRoles] = useState([]); - const [isDropdownOpen, setIsDropdownOpen] = useState(false); // To control dropdown visibility - const dropDownRef = useRef(null); - const inputRef = useRef(null); - const tenantKey = useSelector((state) => state.tenants?.tenantId); - useEffect(() => { - if (openByDefault && inputRef.current && !selectedRoles.length) { - inputRef.current.focus(); - } - }, [openByDefault]); - // Filter roles based on input - useEffect(() => { - const filtered = allRoles.filter( - (role) => - role.toLowerCase().includes(roleInput.toLowerCase()) && - !selectedRoles.includes(role) - ); - setFilteredRoles(filtered); - }, [roleInput, allRoles, selectedRoles]); - - // Handle input change - const handleRoleInputChange = (e) => { - setRoleInput(e.target.value); - }; - - // Handle role selection from dropdown - const handleRoleSelect = (role) => { - setSelectedRoles([...selectedRoles, role]); - setRoleInput(""); // Clear input - setIsDropdownOpen(false); // Close the dropdown after selecting a role - }; - - // Handle role removal - const removeRole = (roleToRemove) => { - setSelectedRoles(selectedRoles.filter((role) => role !== roleToRemove)); - }; - - // Close dropdown when clicking outside - useEffect(() => { - const handleClickOutside = (event) => { - if ( - dropDownRef.current && - !dropDownRef.current.contains(event.target) && - !inputRef.current.contains(event.target) - ) { - setIsDropdownOpen(false); // Close dropdown if clicked outside - } - }; - - document.addEventListener("mousedown", handleClickOutside); - return () => { - document.removeEventListener("mousedown", handleClickOutside); - }; - }, []); - - return ( -
-
- {selectedRoles.map((role, index) => ( - } - bg="primary" - onClick={() => removeRole(role)} - /> - ))} - setIsDropdownOpen(true)} // Open dropdown when input is focused - className="role-input" - ref={inputRef} // Reference to input for outside click handling - /> -
- - {isDropdownOpen && filteredRoles.length > 0 && ( -
- - {filteredRoles.map((role, index) => ( - handleRoleSelect(role)} - > - {HelperServices.removeTenantKeyFromData(role,tenantKey)} - - ))} - -
- )} -
- ); -}; - - -RoleSelector.propTypes = { - allRoles: PropTypes.array, - selectedRoles: PropTypes.array.isRequired, - setSelectedRoles: PropTypes.func.isRequired, - openByDefault: PropTypes.bool, -}; - -export default RoleSelector; diff --git a/forms-flow-web/src/components/Form/EditForm/FormEdit.js b/forms-flow-web/src/components/Form/EditForm/FormEdit.js index fbfe4e1a7..709d8ad03 100644 --- a/forms-flow-web/src/components/Form/EditForm/FormEdit.js +++ b/forms-flow-web/src/components/Form/EditForm/FormEdit.js @@ -61,7 +61,8 @@ import NewVersionModal from "../../Modals/NewVersionModal"; import { currentFormReducer } from "../../../modules/formReducer.js"; import { toast } from "react-toastify"; import userRoles from "../../../constants/permissions.js"; -import { generateUniqueId, isFormComponentsChanged, addTenantkey, textTruncate } from "../../../helper/helper.js"; +import { generateUniqueId, isFormComponentsChanged, addTenantkey, textTruncate, + convertMultiSelectOptionToValue } from "../../../helper/helper.js"; import { useMutation } from "react-query"; import NavigateBlocker from "../../CustomComponents/NavigateBlocker"; import { setProcessData, setFormPreviosData, setFormProcessesData } from "../../../actions/processActions.js"; @@ -538,12 +539,13 @@ const handleSaveLayout = () => { /* ----------- save settings function to be used in settings modal ---------- */ + const filterAuthorizationData = (authorizationData) => { if(authorizationData.selectedOption === "submitter"){ return {roles: [], userName:null, resourceDetails:{submitter:true}}; } if (authorizationData.selectedOption === "specifiedRoles") { - return { roles: authorizationData.selectedRoles, userName: "" }; + return { roles: convertMultiSelectOptionToValue(authorizationData.selectedRoles, "role"), userName: "" }; } return { roles: [], userName: preferred_username }; }; @@ -582,7 +584,7 @@ const handleSaveLayout = () => { resourceDetails: {}, roles: rolesState.FORM.selectedOption === "specifiedRoles" - ? rolesState.FORM.selectedRoles + ? convertMultiSelectOptionToValue(rolesState.FORM.selectedRoles, "role") : [], }, }; diff --git a/forms-flow-web/src/components/Form/EditForm/FormSettings.js b/forms-flow-web/src/components/Form/EditForm/FormSettings.js index b4cfdf43d..57f26466f 100644 --- a/forms-flow-web/src/components/Form/EditForm/FormSettings.js +++ b/forms-flow-web/src/components/Form/EditForm/FormSettings.js @@ -12,10 +12,10 @@ import { FormInput, FormTextArea, } from "@formsflow/components"; +import Multiselect from 'multiselect-react-dropdown'; -import MultiSelectComponent from "../../CustomComponents/MultiSelect"; import { MULTITENANCY_ENABLED } from "../../../constants/constants"; -import { addTenantkeyAsSuffix } from "../../../helper/helper"; +import { addTenantkeyAsSuffix, convertSelectedValueToMultiSelectOption } from "../../../helper/helper"; import { useDispatch, useSelector } from "react-redux"; import { getUserRoles } from "../../../apiManager/services/authorizationService"; import { useTranslation } from "react-i18next"; @@ -64,21 +64,25 @@ const FormSettings = forwardRef((props, ref) => { const publicUrlPath = `${window.location.origin}/public/form/`; const [urlPath,setUrlPath] = useState(publicUrlPath); - const setSelectedOption = (roles, option)=> roles.length ? "specifiedRoles" : option; + const setSelectedOption = (roles = [], option)=> roles.length ? "specifiedRoles" : option; + const multiSlectOptionKey = "role"; /* ------------------------- authorization variables ------------------------ */ const [rolesState, setRolesState] = useState({ DESIGN: { - selectedRoles: formAuthorization.DESIGNER?.roles, + selectedRoles: convertSelectedValueToMultiSelectOption(formAuthorization.DESIGNER?.roles, + multiSlectOptionKey), selectedOption: setSelectedOption(formAuthorization.DESIGNER?.roles,"onlyYou"), }, FORM: { roleInput: "", - selectedRoles: formAuthorization.FORM?.roles, + selectedRoles: convertSelectedValueToMultiSelectOption(formAuthorization.FORM?.roles, + multiSlectOptionKey), selectedOption: setSelectedOption(formAuthorization.FORM?.roles,"registeredUsers"), }, APPLICATION: { roleInput: "", - selectedRoles: formAuthorization.APPLICATION?.roles, + selectedRoles: convertSelectedValueToMultiSelectOption(formAuthorization.APPLICATION?.roles, + multiSlectOptionKey), selectedOption: setSelectedOption(formAuthorization.APPLICATION?.roles, "submitter"), /* The 'submitter' key is stored in 'resourceDetails'. If the roles array is not empty we assume that the submitter is true. */ @@ -154,7 +158,7 @@ const FormSettings = forwardRef((props, ref) => { .then((res) => { if (res) { const { data = [] } = res; - setUserRoles(data.map((role) => role.name)); + setUserRoles(data.map((role,index) => ({[multiSlectOptionKey]:role.name, id: index}))); } }) .catch((error) => console.error("error", error)); @@ -162,7 +166,7 @@ const FormSettings = forwardRef((props, ref) => { - const handleRoleStateChange = (section, key, value) => { + const handleRoleStateChange = (section, key, value = []) => { setRolesState((prevState) => ({ ...prevState, [section]: { @@ -210,6 +214,10 @@ const FormSettings = forwardRef((props, ref) => { props.setIsSaveButtonDisabled(shouldDisableSaveButton); }, [rolesState, errors, formDetails]); + const handleRoleSelectForDesign = (roles) => handleRoleStateChange(DESIGN, "selectedRoles", roles); + const handleRoleSelectForForm = (roles) => handleRoleStateChange(FORM, "selectedRoles", roles); + const handleRoleSelectForApplication = (roles) => + handleRoleStateChange(APPLICATION, "selectedRoles", roles); return ( <> @@ -289,14 +297,15 @@ const FormSettings = forwardRef((props, ref) => { )} {rolesState.DESIGN.selectedOption === "specifiedRoles" && ( - - handleRoleStateChange(DESIGN, "selectedRoles", roles) - } + + )} @@ -338,14 +347,15 @@ const FormSettings = forwardRef((props, ref) => { )} {rolesState.FORM.selectedOption === "specifiedRoles" && ( - - handleRoleStateChange(FORM, "selectedRoles", roles) - } - /> + + )} @@ -378,14 +388,15 @@ const FormSettings = forwardRef((props, ref) => { )} {rolesState.APPLICATION.selectedOption === "specifiedRoles" && ( - - handleRoleStateChange(APPLICATION, "selectedRoles", roles) - } + + )} diff --git a/forms-flow-web/src/helper/helper.js b/forms-flow-web/src/helper/helper.js index ebf8cbd58..aa67ec303 100644 --- a/forms-flow-web/src/helper/helper.js +++ b/forms-flow-web/src/helper/helper.js @@ -114,5 +114,22 @@ const addTenantkeyAsSuffix = (value, tenantkey) => { } }; -export { generateUniqueId, replaceUrl, addTenantkey, removeTenantKey, textTruncate, renderPage, - filterSelectOptionByLabel, isFormComponentsChanged,addTenantkeyAsSuffix}; +/* ----------------- convert data from and into multiselect ----------------- */ +const convertMultiSelectOptionToValue = (selectedValues = [], key) => + selectedValues.map(i=> i[key]); + +const convertSelectedValueToMultiSelectOption = (values = [], key) => + values.map((value)=>({[key]:value, id:_.uniqueId(value)})); +/* ----------------------------------- --- ---------------------------------- */ +export { generateUniqueId, + replaceUrl, + addTenantkey, + removeTenantKey, + textTruncate, + renderPage, + filterSelectOptionByLabel, + isFormComponentsChanged, + addTenantkeyAsSuffix, + convertMultiSelectOptionToValue, + convertSelectedValueToMultiSelectOption +}; From 2feed6a9fd141d4b92d47be449a9c49c62027bd5 Mon Sep 17 00:00:00 2001 From: shuhaib-aot Date: Wed, 15 Jan 2025 12:23:22 +0530 Subject: [PATCH 2/4] fixed sonarcloud issues default parameter --- .../src/components/Form/EditForm/FormSettings.js | 8 ++++---- forms-flow-web/src/helper/helper.js | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/forms-flow-web/src/components/Form/EditForm/FormSettings.js b/forms-flow-web/src/components/Form/EditForm/FormSettings.js index 57f26466f..7608db4d0 100644 --- a/forms-flow-web/src/components/Form/EditForm/FormSettings.js +++ b/forms-flow-web/src/components/Form/EditForm/FormSettings.js @@ -11,8 +11,8 @@ import { CustomRadioButton, FormInput, FormTextArea, + MultipleSelect } from "@formsflow/components"; -import Multiselect from 'multiselect-react-dropdown'; import { MULTITENANCY_ENABLED } from "../../../constants/constants"; import { addTenantkeyAsSuffix, convertSelectedValueToMultiSelectOption } from "../../../helper/helper"; @@ -297,7 +297,7 @@ const FormSettings = forwardRef((props, ref) => { )} {rolesState.DESIGN.selectedOption === "specifiedRoles" && ( - { )} {rolesState.FORM.selectedOption === "specifiedRoles" && ( - { )} {rolesState.APPLICATION.selectedOption === "specifiedRoles" && ( - { }; /* ----------------- convert data from and into multiselect ----------------- */ -const convertMultiSelectOptionToValue = (selectedValues = [], key) => +const convertMultiSelectOptionToValue = (selectedValues = [], key = null) => selectedValues.map(i=> i[key]); -const convertSelectedValueToMultiSelectOption = (values = [], key) => +const convertSelectedValueToMultiSelectOption = (values = [], key = null) => values.map((value)=>({[key]:value, id:_.uniqueId(value)})); /* ----------------------------------- --- ---------------------------------- */ export { generateUniqueId, From 28acfa25a67b6c4c2ad9ec79493582e465f7a85e Mon Sep 17 00:00:00 2001 From: shuhaib-aot Date: Wed, 15 Jan 2025 12:28:25 +0530 Subject: [PATCH 3/4] fixed sonarcloud issues default parameter --- .../src/components/Form/EditForm/FormSettings.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/forms-flow-web/src/components/Form/EditForm/FormSettings.js b/forms-flow-web/src/components/Form/EditForm/FormSettings.js index 7608db4d0..b8871e88f 100644 --- a/forms-flow-web/src/components/Form/EditForm/FormSettings.js +++ b/forms-flow-web/src/components/Form/EditForm/FormSettings.js @@ -64,26 +64,26 @@ const FormSettings = forwardRef((props, ref) => { const publicUrlPath = `${window.location.origin}/public/form/`; const [urlPath,setUrlPath] = useState(publicUrlPath); - const setSelectedOption = (roles = [], option)=> roles.length ? "specifiedRoles" : option; + const setSelectedOption = (option, roles = [])=> roles.length ? "specifiedRoles" : option; const multiSlectOptionKey = "role"; /* ------------------------- authorization variables ------------------------ */ const [rolesState, setRolesState] = useState({ DESIGN: { selectedRoles: convertSelectedValueToMultiSelectOption(formAuthorization.DESIGNER?.roles, multiSlectOptionKey), - selectedOption: setSelectedOption(formAuthorization.DESIGNER?.roles,"onlyYou"), + selectedOption: setSelectedOption("onlyYou", formAuthorization.DESIGNER?.roles), }, FORM: { roleInput: "", selectedRoles: convertSelectedValueToMultiSelectOption(formAuthorization.FORM?.roles, multiSlectOptionKey), - selectedOption: setSelectedOption(formAuthorization.FORM?.roles,"registeredUsers"), + selectedOption: setSelectedOption("registeredUsers", formAuthorization.FORM?.roles), }, APPLICATION: { roleInput: "", selectedRoles: convertSelectedValueToMultiSelectOption(formAuthorization.APPLICATION?.roles, multiSlectOptionKey), - selectedOption: setSelectedOption(formAuthorization.APPLICATION?.roles, "submitter"), + selectedOption: setSelectedOption("submitter", formAuthorization.APPLICATION?.roles), /* The 'submitter' key is stored in 'resourceDetails'. If the roles array is not empty we assume that the submitter is true. */ } From 86ee1b073940bc6bce00c827bc89525c3d1b0889 Mon Sep 17 00:00:00 2001 From: shuhaib-aot Date: Wed, 15 Jan 2025 12:31:09 +0530 Subject: [PATCH 4/4] Fixed typo --- .../src/components/Form/EditForm/FormSettings.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/forms-flow-web/src/components/Form/EditForm/FormSettings.js b/forms-flow-web/src/components/Form/EditForm/FormSettings.js index b8871e88f..2d385367f 100644 --- a/forms-flow-web/src/components/Form/EditForm/FormSettings.js +++ b/forms-flow-web/src/components/Form/EditForm/FormSettings.js @@ -65,24 +65,24 @@ const FormSettings = forwardRef((props, ref) => { const publicUrlPath = `${window.location.origin}/public/form/`; const [urlPath,setUrlPath] = useState(publicUrlPath); const setSelectedOption = (option, roles = [])=> roles.length ? "specifiedRoles" : option; - const multiSlectOptionKey = "role"; + const multiSelectOptionKey = "role"; /* ------------------------- authorization variables ------------------------ */ const [rolesState, setRolesState] = useState({ DESIGN: { selectedRoles: convertSelectedValueToMultiSelectOption(formAuthorization.DESIGNER?.roles, - multiSlectOptionKey), + multiSelectOptionKey), selectedOption: setSelectedOption("onlyYou", formAuthorization.DESIGNER?.roles), }, FORM: { roleInput: "", selectedRoles: convertSelectedValueToMultiSelectOption(formAuthorization.FORM?.roles, - multiSlectOptionKey), + multiSelectOptionKey), selectedOption: setSelectedOption("registeredUsers", formAuthorization.FORM?.roles), }, APPLICATION: { roleInput: "", selectedRoles: convertSelectedValueToMultiSelectOption(formAuthorization.APPLICATION?.roles, - multiSlectOptionKey), + multiSelectOptionKey), selectedOption: setSelectedOption("submitter", formAuthorization.APPLICATION?.roles), /* The 'submitter' key is stored in 'resourceDetails'. If the roles array is not empty we assume that the submitter is true. */ @@ -158,7 +158,7 @@ const FormSettings = forwardRef((props, ref) => { .then((res) => { if (res) { const { data = [] } = res; - setUserRoles(data.map((role,index) => ({[multiSlectOptionKey]:role.name, id: index}))); + setUserRoles(data.map((role,index) => ({[multiSelectOptionKey]:role.name, id: index}))); } }) .catch((error) => console.error("error", error)); @@ -302,7 +302,7 @@ const FormSettings = forwardRef((props, ref) => { selectedValues={rolesState.DESIGN.selectedRoles} onSelect={handleRoleSelectForDesign} onRemove={handleRoleSelectForDesign} - displayValue={multiSlectOptionKey} + displayValue={multiSelectOptionKey} avoidHighlightFirstOption={true} /> @@ -352,7 +352,7 @@ const FormSettings = forwardRef((props, ref) => { selectedValues={rolesState.FORM.selectedRoles} // Preselected value to persist in dropdown onSelect={handleRoleSelectForForm} // Function will trigger on select event onRemove={handleRoleSelectForForm} // Function will trigger on remove event - displayValue={multiSlectOptionKey} // Property name to display in the dropdown options + displayValue={multiSelectOptionKey} // Property name to display in the dropdown options avoidHighlightFirstOption={true} /> @@ -393,7 +393,7 @@ const FormSettings = forwardRef((props, ref) => { selectedValues={rolesState.APPLICATION.selectedRoles} // Preselected value to persist in dropdown onSelect={handleRoleSelectForApplication} // Function will trigger on select event onRemove={handleRoleSelectForApplication} // Function will trigger on remove event - displayValue={multiSlectOptionKey} // Property name to display in the dropdown options + displayValue={multiSelectOptionKey} // Property name to display in the dropdown options avoidHighlightFirstOption={true} />