@@ -6,18 +6,20 @@ import InputField from "../components/InputField.jsx";
66import { useAppStore } from "../stores/AppStore.js" ;
77import { useShallow } from "zustand/react/shallow" ;
88import { deletePolicy , newPolicy , uniquePolicyName , updatePolicy } from "../api/index.js" ;
9- import { isEmpty } from "../utils/Utils.js" ;
9+ import { isEmpty , splitListSemantically } from "../utils/Utils.js" ;
1010import ErrorIndicator from "../components/ErrorIndicator.jsx" ;
1111import SelectField from "../components/SelectField.jsx" ;
1212import { defaultAttributes , flatMapByValues , policyDesscription } from "../utils/Policy.js" ;
1313import TrashIcon from "@surfnet/sds/icons/functional-icons/bin.svg" ;
1414import ConfirmationDialog from "../components/ConfirmationDialog.jsx" ;
1515
16+
1617export const PolicyForm = ( { policy, setPolicy, isExistingPolicy, originalName, refreshPolicies} ) => {
1718
1819 const [ initial , setInitial ] = useState ( true ) ;
1920 const [ duplicatePolicyName , setDuplicatePolicyName ] = useState ( false ) ;
2021 const [ confirmation , setConfirmation ] = useState ( { } ) ;
22+ const [ attributeValueErrors , setAttributeValueErrors ] = useState ( { } ) ;
2123
2224 const required = [ "name" , "denyAdvice" , "denyAdviceNl" ] ;
2325
@@ -31,7 +33,8 @@ export const PolicyForm = ({policy, setPolicy, isExistingPolicy, originalName, r
3133 }
3234
3335 const isValid = ( ) => {
34- return required . every ( attr => ! isEmpty ( policy . data [ attr ] ) ) && ! duplicatePolicyName ;
36+ const allAttributesValuesValid = Object . values ( attributeValueErrors ) . every ( values => isEmpty ( values ) ) ;
37+ return required . every ( attr => ! isEmpty ( policy . data [ attr ] ) ) && ! duplicatePolicyName && allAttributesValuesValid ;
3538 }
3639
3740 const doDeletePolicy = ( confirmationRequired , policy ) => {
@@ -93,14 +96,23 @@ export const PolicyForm = ({policy, setPolicy, isExistingPolicy, originalName, r
9396
9497 const attributeDeleted = index => {
9598 const newAttributes = policy . data . attributes . filter ( ( item , i ) => i !== index ) ;
96- internalUpdatePolicy ( { attributes : defaultAttributes ( newAttributes ) } )
99+ internalUpdatePolicy ( { attributes : defaultAttributes ( newAttributes ) } ) ;
100+ const deletedAttribute = policy . data . attributes [ index ] ;
101+ delete attributeValueErrors [ deletedAttribute . name ] ;
102+ setAttributeValueErrors ( { ...attributeValueErrors } ) ;
97103 }
98104
99- const attributeValueChanged = ( value , index ) => {
105+ const attributeValueChanged = ( values , index ) => {
100106 const newAttributes = [ ...policy . data . attributes ] ;
101107 const attribute = newAttributes [ index ] ;
102- attribute . value = value ;
103- internalUpdatePolicy ( { attributes : newAttributes } )
108+ attribute . value = values ;
109+ internalUpdatePolicy ( { attributes : newAttributes } ) ;
110+ const validationRegex = allowedAttributes . find ( attr => attr . value === attribute . name ) . validationRegex ;
111+ const regex = new RegExp ( validationRegex ) ;
112+ const invalidValues = values
113+ . map ( value => value . value )
114+ . filter ( value => ! regex . test ( value ) ) ;
115+ setAttributeValueErrors ( { ...attributeValueErrors , [ attribute . name ] : invalidValues } ) ;
104116 }
105117
106118 const denyRuleToggle = val => {
@@ -163,7 +175,6 @@ export const PolicyForm = ({policy, setPolicy, isExistingPolicy, originalName, r
163175 { duplicatePolicyName &&
164176 < ErrorIndicator adjustMargin = { true }
165177 msg = { I18n . t ( "appAccess.duplicateName" , { name : policy . data . name } ) } /> }
166-
167178 < div className = "row" >
168179 < div className = "row-item" >
169180 < span className = "label standalone" > { I18n . t ( "appAccess.allowDeny" ) }
@@ -210,6 +221,15 @@ export const PolicyForm = ({policy, setPolicy, isExistingPolicy, originalName, r
210221 placeholder = { I18n . t ( "appAccess.permittedValuesPlaceholder" ) }
211222 onChange = { values => attributeValueChanged ( values , index ) }
212223 />
224+ { ! isEmpty ( attributeValueErrors [ attribute . name ] ) &&
225+ < ErrorIndicator adjustMargin = { false }
226+ msg = { I18n . t ( "appAccess.attributeValueErrors" ,
227+ {
228+ name : allowedAttributes . find ( attr => attr . value === attribute . name ) . label ,
229+ values : splitListSemantically (
230+ attributeValueErrors [ attribute . name ] . map ( val => `'${ val } '` ) ,
231+ I18n . t ( "forms.and" ) )
232+ } ) } /> }
213233 </ div > ) }
214234 { policy . data . attributes . every ( attribute => attribute . name && ! isEmpty ( attribute . value ) ) &&
215235 < div className = "add-attribute-container" >
0 commit comments