diff --git a/apps/meteor/client/views/admin/ABAC/ABACAttributesTab/AttributesContextualBar.tsx b/apps/meteor/client/views/admin/ABAC/ABACAttributesTab/AttributesContextualBar.tsx index 78990e95b6b83..a41e7b6b87ca2 100644 --- a/apps/meteor/client/views/admin/ABAC/ABACAttributesTab/AttributesContextualBar.tsx +++ b/apps/meteor/client/views/admin/ABAC/ABACAttributesTab/AttributesContextualBar.tsx @@ -38,6 +38,7 @@ const AttributesContextualBar = ({ attributeData, onClose }: AttributesContextua attributeValues: [{ value: '' }], lockedAttributes: [], }, + mode: 'onChange', }); const { getValues } = methods; @@ -74,7 +75,7 @@ const AttributesContextualBar = ({ attributeData, onClose }: AttributesContextua dispatchToastMessage({ type: 'error', message: error }); }, onSettled: () => { - queryClient.invalidateQueries({ queryKey: ABACQueryKeys.roomAttributes.all() }); + queryClient.invalidateQueries({ queryKey: ABACQueryKeys.roomAttributes.list() }); }, }); diff --git a/apps/meteor/client/views/admin/ABAC/ABACAttributesTab/AttributesForm.tsx b/apps/meteor/client/views/admin/ABAC/ABACAttributesTab/AttributesForm.tsx index 390e4eccf2ba6..35a83d97d30ca 100644 --- a/apps/meteor/client/views/admin/ABAC/ABACAttributesTab/AttributesForm.tsx +++ b/apps/meteor/client/views/admin/ABAC/ABACAttributesTab/AttributesForm.tsx @@ -11,7 +11,7 @@ import { TextInput, } from '@rocket.chat/fuselage'; import { ContextualbarScrollableContent } from '@rocket.chat/ui-client'; -import { useCallback, useId, useMemo } from 'react'; +import { useCallback, useId, useMemo, Fragment } from 'react'; import { useFieldArray, useFormContext } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; @@ -35,29 +35,42 @@ const AttributesForm = ({ onSave, onCancel, description }: AttributesFormProps) watch, } = useFormContext(); + const { t } = useTranslation(); + + const attributeValues = watch('attributeValues'); + const lockedAttributes = watch('lockedAttributes'); + const { fields: lockedAttributesFields, remove: removeLockedAttribute } = useFieldArray({ name: 'lockedAttributes', }); + const validateRepeatedValues = useCallback( + (value: string) => { + // Only one instance of the same attribute value is allowed to be in the form at a time + const repeatedAttributes = [...lockedAttributes, ...attributeValues].filter((attribute) => attribute.value === value).length > 1; + return repeatedAttributes ? t('ABAC_No_repeated_values') : undefined; + }, + [lockedAttributes, attributeValues, t], + ); + const { fields, append, remove } = useFieldArray({ name: 'attributeValues', rules: { minLength: 1, }, }); - const { t } = useTranslation(); const formId = useId(); const nameField = useId(); const valuesField = useId(); - const attributeValues = watch('attributeValues'); const getAttributeValuesError = useCallback(() => { if (errors.attributeValues?.length && errors.attributeValues?.length > 0) { - return t('Required_field', { field: t('Values') }); + return errors.attributeValues[0]?.value?.message; } + return ''; - }, [errors.attributeValues, t]); + }, [errors.attributeValues]); const hasValuesErrors = useMemo(() => { const attributeValuesErrors = Array.isArray(errors?.attributeValues) && errors.attributeValues.some((error) => !!error?.value?.message); @@ -82,36 +95,49 @@ const AttributesForm = ({ onSave, onCancel, description }: AttributesFormProps) {...register('name', { required: t('Required_field', { field: t('Name') }) })} /> - {errors.name?.message || ''} + {errors.name && {errors.name.message}} {t('Values')} {lockedAttributesFields.map((field, index) => ( - - - {index !== 0 && removeLockedAttribute(index)} />} - + + + validateRepeatedValues(value), + })} + /> + {index !== 0 && ( + removeLockedAttribute(index)} /> + )} + + {errors.lockedAttributes?.[index]?.value && {errors.lockedAttributes?.[index]?.value?.message}} + ))} {fields.map((field, index) => ( - - - {(index !== 0 || lockedAttributesFields.length > 0) && ( - remove(index)} /> - )} - + + + validateRepeatedValues(value), + })} + /> + {(index !== 0 || lockedAttributesFields.length > 0) && ( + remove(index)} /> + )} + + {errors.attributeValues?.[index]?.value && {errors.attributeValues[index].value.message}} + ))} - {getAttributeValuesError()} -