diff --git a/security-admin/src/main/webapp/react-webapp/src/components/CommonComponents.jsx b/security-admin/src/main/webapp/react-webapp/src/components/CommonComponents.jsx index 85a361dd35..57c9290d40 100644 --- a/security-admin/src/main/webapp/react-webapp/src/components/CommonComponents.jsx +++ b/security-admin/src/main/webapp/react-webapp/src/components/CommonComponents.jsx @@ -24,8 +24,9 @@ import { Alert, Badge, Button, OverlayTrigger, Popover } from "react-bootstrap"; import { Field } from "react-final-form"; import { useLocation } from "react-router-dom"; import blockLoading from "Images/blockLoading.gif"; +import { toast } from "react-toastify"; -const Loader = () => { +export const Loader = () => { return (
@@ -570,4 +571,11 @@ export const ModalLoader = () => { ); }; -export { Loader }; +export const trimInputValue = (e, input) => { + const value = e.target.value; + const trimmed = value.trim(); + if (value !== trimmed) { + input.onChange(trimmed); + } + input.onBlur(e); // Always call onBlur to trigger validation +}; diff --git a/security-admin/src/main/webapp/react-webapp/src/components/CreatableField.jsx b/security-admin/src/main/webapp/react-webapp/src/components/CreatableField.jsx index 4433044303..2cbc0b9d9c 100644 --- a/security-admin/src/main/webapp/react-webapp/src/components/CreatableField.jsx +++ b/security-admin/src/main/webapp/react-webapp/src/components/CreatableField.jsx @@ -45,15 +45,18 @@ const CreatableField = (props) => { case "Enter": case "Tab": setActionInputValue(""); - setActionValue([...actionValue, createOption(actionInputValue)]); - creatableOnChange([...actionValue, createOption(actionInputValue)]); + setActionValue([...actionValue, createOption(actionInputValue.trim())]); + creatableOnChange([ + ...actionValue, + createOption(actionInputValue.trim()) + ]); e.preventDefault(); } }; const createOption = (label) => ({ - value: label, - label: label + value: label.trim(), + label: label.trim() }); const handleInputChange = (value) => { diff --git a/security-admin/src/main/webapp/react-webapp/src/components/Editable.jsx b/security-admin/src/main/webapp/react-webapp/src/components/Editable.jsx index 9d1234d2b0..6586a662e0 100644 --- a/security-admin/src/main/webapp/react-webapp/src/components/Editable.jsx +++ b/security-admin/src/main/webapp/react-webapp/src/components/Editable.jsx @@ -303,6 +303,24 @@ const CustomCondition = (props) => { width="500px" isClearable={false} styles={selectInputCustomStyles} + formatCreateLabel={(inputValue) => + `Create "${inputValue.trim()}"` + } + onCreateOption={(inputValue) => { + const trimmedValue = inputValue.trim(); + if (trimmedValue) { + const newOption = { + label: trimmedValue, + value: trimmedValue + }; + const currentValues = selectedInputVal || []; + const newValues = Array.isArray(currentValues) + ? [...currentValues, newOption] + : [newOption]; + setSelectVal(newValues); + tagAccessData(newValues, m.name); + } + }} />
diff --git a/security-admin/src/main/webapp/react-webapp/src/utils/XAEnums.js b/security-admin/src/main/webapp/react-webapp/src/utils/XAEnums.js index ac9bdfb30a..4e08f3a061 100755 --- a/security-admin/src/main/webapp/react-webapp/src/utils/XAEnums.js +++ b/security-admin/src/main/webapp/react-webapp/src/utils/XAEnums.js @@ -586,7 +586,7 @@ export const RegexValidation = { /^([A-Za-z0-9_]|[\u00C0-\u017F])([a-z0-9,._\-+/@= ]|[\u00C0-\u017F])+$/i, regexExpressionForFirstAndLastName: /^([A-Za-z0-9_]|[\u00C0-\u017F])([a-zA-Z0-9\s_. -@]|[\u00C0-\u017F])+$/i, - regexforNameValidation: /^[a-zA-Z0-9_-][a-zA-Z0-9\s_-]{0,254}$/, + regexForNameValidation: /^[a-zA-Z0-9_-][a-zA-Z0-9\s_-]{0,254}$/, regexExpressionForSecondaryName: /^([A-Za-z0-9_]|[\u00C0-\u017F])([a-zA-Z0-9\s_. -@]|[\u00C0-\u017F])+$/i, regexforServiceNameValidation: /^[a-zA-Z0-9_-][a-zA-Z0-9_-]{0,254}$/, @@ -601,7 +601,7 @@ export const RegexValidation = { 3. Name length should be greater than one." ), - regexforNameValidationMessage: + regexForNameValidationMessage: "Name should not start with space, it should be less than 256 characters and special characters are not allowed(except _ - and space).", secondaryNameValidationMessage: ( <> diff --git a/security-admin/src/main/webapp/react-webapp/src/utils/XAMessages.js b/security-admin/src/main/webapp/react-webapp/src/utils/XAMessages.js index ee7b010ea4..75b0647580 100644 --- a/security-admin/src/main/webapp/react-webapp/src/utils/XAMessages.js +++ b/security-admin/src/main/webapp/react-webapp/src/utils/XAMessages.js @@ -36,9 +36,9 @@ export const RegexMessage = {

), - passwordvalidationinfomessage: - "Password should be minimum 8 characters ,atleast one uppercase letter, one lowercase letter and one numeric. For FIPS environment password should be minimum 14 characters with atleast one uppercase letter, one special characters, one lowercase letter and one numeric.", - emailvalidationinfomessage: ( + passwordValidationInfoMessage: + "Password should be minimum 8 characters ,at least one uppercase letter, one lowercase letter and one numeric. For FIPS environment password should be minimum 14 characters with atleast one uppercase letter, one special characters, one lowercase letter and one numeric.", + emailValidationInfoMessage: ( <>

1. Email address should be start with alphabet / numeric / underscore diff --git a/security-admin/src/main/webapp/react-webapp/src/views/Encryption/KeyCreate.jsx b/security-admin/src/main/webapp/react-webapp/src/views/Encryption/KeyCreate.jsx index 5a9fe069b6..9e8773ca54 100644 --- a/security-admin/src/main/webapp/react-webapp/src/views/Encryption/KeyCreate.jsx +++ b/security-admin/src/main/webapp/react-webapp/src/views/Encryption/KeyCreate.jsx @@ -61,7 +61,7 @@ const keyCreateReducer = (state, action) => { } }; -const PromtDialog = (props) => { +const PromptDialog = (props) => { const { isDirtyField, isUnblock } = props; usePrompt("Are you sure you want to leave", isDirtyField && !isUnblock); return null; @@ -225,7 +225,7 @@ function KeyCreate(props) { } }) => (

- +
{ handleSubmit(event); diff --git a/security-admin/src/main/webapp/react-webapp/src/views/PolicyListing/AddUpdatePolicyForm.jsx b/security-admin/src/main/webapp/react-webapp/src/views/PolicyListing/AddUpdatePolicyForm.jsx index e6b2825c26..898e70aeb2 100644 --- a/security-admin/src/main/webapp/react-webapp/src/views/PolicyListing/AddUpdatePolicyForm.jsx +++ b/security-admin/src/main/webapp/react-webapp/src/views/PolicyListing/AddUpdatePolicyForm.jsx @@ -53,7 +53,8 @@ import { BlockUi, Loader, scrollToError, - selectInputCustomStyles + selectInputCustomStyles, + trimInputValue } from "Components/CommonComponents"; import { fetchApi } from "Utils/fetchAPI"; import { RangerPolicyType, getEnumElementByValue } from "Utils/XAEnums"; @@ -62,19 +63,20 @@ import PolicyPermissionItem from "../PolicyListing/PolicyPermissionItem"; import { useParams, useNavigate, useLocation } from "react-router-dom"; import PolicyValidityPeriodComp from "./PolicyValidityPeriodComp"; import PolicyConditionsComp from "./PolicyConditionsComp"; -import { getAllTimeZoneList, policyConditionUpdatedJSON } from "Utils/XAUtils"; import moment from "moment"; import { InfoIcon, commonBreadcrumb, isPolicyExpired, - getResourcesDefVal + getResourcesDefVal, + getAllTimeZoneList, + policyConditionUpdatedJSON, + policyInfo } from "Utils/XAUtils"; import { useAccordionButton } from "react-bootstrap/AccordionButton"; import AccordionContext from "react-bootstrap/AccordionContext"; import usePrompt from "Hooks/usePrompt"; import { RegexMessage } from "Utils/XAMessages"; -import { policyInfo } from "Utils/XAUtils"; import { getServiceDef } from "Utils/appState"; import { FieldArray } from "react-final-form-arrays"; @@ -290,7 +292,7 @@ export default function AddUpdatePolicyForm() { const fetchPolicyLabel = async (inputValue) => { let params = {}; if (inputValue) { - params["policyLabel"] = inputValue || ""; + params["policyLabel"] = inputValue.trim() || ""; } const policyLabelResp = await fetchApi({ url: "plugins/policyLabels", @@ -298,8 +300,8 @@ export default function AddUpdatePolicyForm() { }); return policyLabelResp.data.map((name) => ({ - label: name, - value: name + label: name.trim(), + value: name.trim() })); }; @@ -387,15 +389,15 @@ export default function AddUpdatePolicyForm() { }); } if (policyId) { - data.policyName = policyData?.name; + data.policyName = policyData?.name?.trim(); data.isEnabled = policyData?.isEnabled; data.policyPriority = policyData?.policyPriority == 0 ? false : true; - data.description = policyData?.description; + data.description = policyData?.description?.trim(); data.isAuditEnabled = policyData?.isAuditEnabled; data.policyLabel = policyData && policyData?.policyLabels?.map((val) => { - return { label: val, value: val }; + return { label: val?.trim(), value: val?.trim() }; }); if (policyData?.resources) { if (!isMultiResources) { @@ -404,7 +406,7 @@ export default function AddUpdatePolicyForm() { let setResources = find(serviceCompResourcesDetails, ["name", key]); data[`resourceName-${setResources?.level}`] = setResources; data[`value-${setResources?.level}`] = value.values.map((m) => { - return { label: m, value: m }; + return { label: m?.trim(), value: m?.trim() }; }); if (setResources?.excludesSupported) { data[`isExcludesSupport-${setResources?.level}`] = @@ -449,7 +451,7 @@ export default function AddUpdatePolicyForm() { setResources; additionalResourcesObj[`value-${setResources?.level}`] = value.values.map((m) => { - return { label: m, value: m }; + return { label: m?.trim(), value: m?.trim() }; }); if (setResources?.excludesSupported) { additionalResourcesObj[ @@ -888,7 +890,7 @@ export default function AddUpdatePolicyForm() { data["conditions"] = []; } - /* For create zoen policy*/ + /* For create zone policy*/ if (localStorage.getItem("zoneDetails") != null) { data["zoneName"] = JSON.parse(localStorage.getItem("zoneDetails")).label; } @@ -1299,6 +1301,7 @@ export default function AddUpdatePolicyForm() { : "form-control" } data-cy="policyName" + onBlur={(e) => trimInputValue(e, input)} /> + `Create "${inputValue.trim()}"` + } + // Add this prop to trim the value when a tag is created + onCreateOption={(inputValue) => { + const policyLabelVal = inputValue.trim(); + if (policyLabelVal) { + input.onChange([ + ...input.value, + { + label: policyLabelVal, + value: policyLabelVal + } + ]); + } + }} /> @@ -1421,6 +1441,7 @@ export default function AddUpdatePolicyForm() { as="textarea" rows={3} data-cy="description" + onBlur={(e) => trimInputValue(e, input)} /> diff --git a/security-admin/src/main/webapp/react-webapp/src/views/Resources/ResourceComp.jsx b/security-admin/src/main/webapp/react-webapp/src/views/Resources/ResourceComp.jsx index 661e8237dd..373d83b8fa 100644 --- a/security-admin/src/main/webapp/react-webapp/src/views/Resources/ResourceComp.jsx +++ b/security-admin/src/main/webapp/react-webapp/src/views/Resources/ResourceComp.jsx @@ -134,17 +134,17 @@ export default function ResourceComp(props) { delete formValues[`isRecursiveSupport-${levelKey}`]; } delete formValues[`value-${grpResourcesKeys[index]}`]; - let CurrentSelectedResourcs = selectedVal.name; + let currentSelectedResources = selectedVal.name; for (let j = index + 1; j < grpResourcesKeys.length; j++) { let level = grpResourcesKeys[j]; let nextResource = resources.find((m) => { if (m?.parent) { - return m.parent === CurrentSelectedResourcs; + return m.parent === currentSelectedResources; } }); if (nextResource) { formValues[`resourceName-${level}`] = nextResource; - CurrentSelectedResourcs = nextResource.name; + currentSelectedResources = nextResource.name; } } diff --git a/security-admin/src/main/webapp/react-webapp/src/views/Resources/ResourceSelectComp.jsx b/security-admin/src/main/webapp/react-webapp/src/views/Resources/ResourceSelectComp.jsx index 128796f559..46b2cddfad 100644 --- a/security-admin/src/main/webapp/react-webapp/src/views/Resources/ResourceSelectComp.jsx +++ b/security-admin/src/main/webapp/react-webapp/src/views/Resources/ResourceSelectComp.jsx @@ -93,7 +93,7 @@ export default function ResourceSelectComp(props) { toastId.current = toast.error(error.response.data.msgDesc); } else { toastId.current = toast.error( - "Resouce lookup failed for current resource" + "Resource lookup failed for current resource" ); } } @@ -216,6 +216,18 @@ export default function ResourceSelectComp(props) { filterOption={customFilterOptions} isLoading={isLoading} styles={selectInputCustomStyles} + formatCreateLabel={(inputValue) => `Create "${inputValue.trim()}"`} + onCreateOption={(inputValue) => { + const trimmedValue = inputValue.trim(); + if (trimmedValue) { + const newOption = { label: trimmedValue, value: trimmedValue }; + const currentValue = input.value || []; + const newValue = isArray(currentValue) + ? [...currentValue, newOption] + : [newOption]; + input.onChange(newValue); + } + }} /> {formValues && formValues[`resourceName-${levelKey}`]?.mandatory && diff --git a/security-admin/src/main/webapp/react-webapp/src/views/SecurityZone/SecurityZoneForm.jsx b/security-admin/src/main/webapp/react-webapp/src/views/SecurityZone/SecurityZoneForm.jsx index 12a3764582..3370059825 100644 --- a/security-admin/src/main/webapp/react-webapp/src/views/SecurityZone/SecurityZoneForm.jsx +++ b/security-admin/src/main/webapp/react-webapp/src/views/SecurityZone/SecurityZoneForm.jsx @@ -48,7 +48,8 @@ import { Loader, scrollToError, selectInputCustomStyles, - selectInputCustomErrorStyles + selectInputCustomErrorStyles, + trimInputValue } from "Components/CommonComponents"; import usePrompt from "Hooks/usePrompt"; import { getServiceDef } from "Utils/appState"; @@ -58,7 +59,7 @@ const noneOptions = { value: "none" }; -const PromtDialog = (props) => { +const PromptDialog = (props) => { const { isDirtyField, isUnblock } = props; usePrompt("Are you sure you want to leave", isDirtyField && !isUnblock); return null; @@ -75,10 +76,10 @@ const SecurityZoneForm = () => { const [resourceService, setResourceService] = useState({}); const [resourceServicesOpt, setResourceServicesOpt] = useState([]); const [loader, setLoader] = useState(true); - const [modelState, setModalstate] = useState({ + const [modelState, setModalState] = useState({ showModalResource: false, data: null, - inputval: null, + inputVal: null, index: 0 }); const [preventUnBlock, setPreventUnblock] = useState(false); @@ -93,7 +94,7 @@ const SecurityZoneForm = () => { const [defaultTagServiceOptions, setDefaultTagServiceOptions] = useState([]); useEffect(() => { - fetchInitalData(); + fetchInitialData(); }, [params.zoneId]); const validate = (values) => { @@ -105,12 +106,12 @@ const SecurityZoneForm = () => { }; } else { if ( - !RegexValidation.NAME_VALIDATION.regexforNameValidation.test( + !RegexValidation.NAME_VALIDATION.regexForNameValidation.test( values.name ) ) { errors.name = { - text: RegexValidation.NAME_VALIDATION.regexforNameValidationMessage + text: RegexValidation.NAME_VALIDATION.regexForNameValidationMessage }; } } @@ -122,7 +123,7 @@ const SecurityZoneForm = () => { ) { errors.adminRoles = { required: true, - text: "Please provide atleast one admin user or group or role !" + text: "Please provide at least one admin user or group or role !" }; errors.adminUserGroups = { required: true, @@ -156,15 +157,15 @@ const SecurityZoneForm = () => { }; const handleClose = () => { - setModalstate({ + setModalState({ showModalResource: false, data: null, - inputval: null, + inputVal: null, index: 0 }); }; - const fetchInitalData = async () => { + const fetchInitialData = async () => { await fetchResourceServices(); await fetchZones(); }; @@ -236,10 +237,10 @@ const SecurityZoneForm = () => { } } - setModalstate({ + setModalState({ showModalResource: true, data: {}, - inputval: resourceInput, + inputVal: resourceInput, index: -1 }); @@ -263,10 +264,10 @@ const SecurityZoneForm = () => { } } - setModalstate({ + setModalState({ showModalResource: true, data: editData, - inputval: resourceInput, + inputVal: resourceInput, index: resourceIndex }); @@ -407,8 +408,8 @@ const SecurityZoneForm = () => { const EditFormData = () => { const zoneData = {}; - zoneData.name = zone.name; - zoneData.description = zone.description; + zoneData.name = zone?.name?.trim(); + zoneData.description = zone?.description?.trim(); zoneData.adminUserGroups = []; if (zone.adminUserGroups) { @@ -633,14 +634,14 @@ const SecurityZoneForm = () => { const handleSave = () => { if (modelState.index === -1) { let add = []; - add = modelState.inputval.input.value; + add = modelState.inputVal.input.value; add.push(modelState.data); - modelState.inputval.input.onChange(add); + modelState.inputVal.input.onChange(add); handleClose(); } else { - let edit = modelState.inputval.input.value; + let edit = modelState.inputVal.input.value; edit[modelState.index] = modelState.data; - modelState.inputval.input.onChange(edit); + modelState.inputVal.input.onChange(edit); handleClose(); } }; @@ -776,7 +777,7 @@ const SecurityZoneForm = () => { submitting }) => ( - + { @@ -805,6 +806,7 @@ const SecurityZoneForm = () => { : "form-control" } data-cy="name" + onBlur={(e) => trimInputValue(e, input)} /> {meta.error && meta.touched && ( @@ -829,6 +831,7 @@ const SecurityZoneForm = () => { {...input} className="form-control" data-cy="description" + onBlur={(e) => trimInputValue(e, input)} /> diff --git a/security-admin/src/main/webapp/react-webapp/src/views/ServiceManager/ServiceForm.jsx b/security-admin/src/main/webapp/react-webapp/src/views/ServiceManager/ServiceForm.jsx index 40d871904f..65fcbae842 100644 --- a/security-admin/src/main/webapp/react-webapp/src/views/ServiceManager/ServiceForm.jsx +++ b/security-admin/src/main/webapp/react-webapp/src/views/ServiceManager/ServiceForm.jsx @@ -42,7 +42,8 @@ import { CustomPopover, Loader, scrollToError, - selectInputCustomStyles + selectInputCustomStyles, + trimInputValue } from "Components/CommonComponents"; import { difference, @@ -387,8 +388,8 @@ class ServiceForm extends Component { const serviceJson = {}; serviceJson["name"] = serviceResp?.data?.name; - serviceJson["displayName"] = serviceResp?.data?.displayName; - serviceJson["description"] = serviceResp?.data?.description; + serviceJson["displayName"] = serviceResp?.data?.displayName?.trim(); + serviceJson["description"] = serviceResp?.data?.description?.trim(); serviceJson["isEnabled"] = JSON.stringify(serviceResp?.data?.isEnabled); serviceJson["tagService"] = @@ -409,7 +410,7 @@ class ServiceForm extends Component { serviceDefConfigs.map((config) => { serviceJson["configs"][config.replaceAll(".", "_").replaceAll("-", "_")] = - serviceResp?.data?.configs?.[config]; + serviceResp?.data?.configs?.[config]?.trim(); }); const additionalConfigs = intersection( @@ -435,7 +436,10 @@ class ServiceForm extends Component { let editCustomConfigs = sortBy( difference(serviceCustomConfigs, additionalConfigs)?.map((config) => { - return { name: config, value: serviceResp?.data?.configs[config] }; + return { + name: config?.trim(), + value: serviceResp?.data?.configs[config]?.trim() + }; }), "name" ); @@ -762,6 +766,7 @@ class ServiceForm extends Component { data-cy={ "configs." + this.configsJson[configParam.name] } + onBlur={(e) => trimInputValue(e, input)} /> {configInfo.length === 1 && ( @@ -972,8 +977,8 @@ class ServiceForm extends Component { : undefined; validateDisplayName = (value) => - !RegexValidation.NAME_VALIDATION.regexforNameValidation.test(value) - ? RegexValidation.NAME_VALIDATION.regexforNameValidationMessage + !RegexValidation.NAME_VALIDATION.regexForNameValidation.test(value) + ? RegexValidation.NAME_VALIDATION.regexForNameValidationMessage : undefined; composeValidators = @@ -1209,6 +1214,7 @@ class ServiceForm extends Component { : "form-control" } data-cy="displayName" + onBlur={(e) => trimInputValue(e, input)} /> {meta.error && meta.touched && ( @@ -1236,6 +1242,7 @@ class ServiceForm extends Component { : "form-control" } data-cy="description" + onBlur={(e) => trimInputValue(e, input)} /> {meta.error && meta.touched && ( @@ -1334,22 +1341,34 @@ class ServiceForm extends Component { fields.map((name, index) => ( - + + {({ input, meta }) => ( + + trimInputValue(e, input) + } + /> + )} + - + + {({ input, meta }) => ( + + trimInputValue(e, input) + } + /> + )} +