Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions admin-ui/app/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ const i18nConfig: InitOptions = {
react: {
useSuspense: false,
},
interpolation: {
escapeValue: false, // React already escapes HTML for XSS protection, so we don't need i18next to escape
// This prevents double-escaping which causes ' to appear instead of '
},
}

i18n.use(initReactI18next).init(i18nConfig)
Expand Down
4 changes: 3 additions & 1 deletion admin-ui/app/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -915,7 +915,9 @@
"attribute_update_failed": "Error updating attribute",
"attribute_delete_failed": "Error deleting attribute",
"attribute_load_failed": "Error loading attribute",
"attribute_not_found": "Attribute not found"
"cannot_contain_spaces": "{{field}} cannot contain spaces",
"cannot_be_empty": "{{field}} cannot be empty",
"must_be_valid_url": "{{field}} must be a valid URL"
},
"tooltips": {
"add_attribute": "Add attribute",
Expand Down
4 changes: 3 additions & 1 deletion admin-ui/app/locales/es/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -911,7 +911,9 @@
"attribute_update_failed": "Error al actualizar el atributo",
"attribute_delete_failed": "Error al eliminar el atributo",
"attribute_load_failed": "Error al cargar el atributo",
"attribute_not_found": "Atributo no encontrado"
"cannot_contain_spaces": "{{field}} no puede contener espacios",
"cannot_be_empty": "{{field}} no puede estar vacío",
"must_be_valid_url": "{{field}} debe ser una URL válida"
},
"tooltips": {
"add_attribute": "Añadir atributo",
Expand Down
4 changes: 3 additions & 1 deletion admin-ui/app/locales/fr/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -851,7 +851,9 @@
"attribute_update_failed": "Erreur lors de la mise à jour de l'attribut",
"attribute_delete_failed": "Erreur lors de la suppression de l'attribut",
"attribute_load_failed": "Erreur lors du chargement de l'attribut",
"attribute_not_found": "Attribut introuvable"
"cannot_contain_spaces": "{{field}} ne peut pas contenir d'espaces",
"cannot_be_empty": "{{field}} ne peut pas être vide",
"must_be_valid_url": "{{field}} doit être une URL valide"
},
"tooltips": {
"add_attribute": "Ajouter un attribut",
Expand Down
4 changes: 3 additions & 1 deletion admin-ui/app/locales/pt/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -846,7 +846,9 @@
"attribute_update_failed": "Erro ao atualizar atributo",
"attribute_delete_failed": "Erro ao excluir atributo",
"attribute_load_failed": "Erro ao carregar atributo",
"attribute_not_found": "Atributo não encontrado"
"cannot_contain_spaces": "{{field}} não pode conter espaços",
"cannot_be_empty": "{{field}} não pode estar vazio",
"must_be_valid_url": "{{field}} deve ser uma URL válida"
},
"tooltips": {
"add_attribute": "Adicionar atributo",
Expand Down
1 change: 1 addition & 0 deletions admin-ui/app/routes/Apps/Gluu/GluuInputRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ function GluuInputRow({
formik.handleChange(event)
}
}}
onBlur={formik.handleBlur}
onFocus={onFocus}
onKeyDown={(evt) => evt.key === 'e' && type === 'number' && evt.preventDefault()}
disabled={disabled}
Expand Down
33 changes: 21 additions & 12 deletions admin-ui/plugins/fido/components/DynamicConfiguration.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState, useCallback, useMemo } from 'react'
import React, { useState, useCallback, useEffect, useMemo } from 'react'
import { useFormik } from 'formik'
import { Row, Col, Form, FormGroup } from 'Components'
import GluuInputRow from 'Routes/Apps/Gluu/GluuInputRow'
Expand All @@ -23,17 +23,30 @@ const DynamicConfiguration: React.FC<DynamicConfigurationProps> = ({
setModal((prev) => !prev)
}, [])

const initialValues = useMemo<DynamicConfigFormValues>(
() =>
transformToFormValues(fidoConfiguration, fidoConstants.DYNAMIC) as DynamicConfigFormValues,
[fidoConfiguration],
)

const formik = useFormik<DynamicConfigFormValues>({
initialValues: transformToFormValues(
fidoConfiguration,
fidoConstants.DYNAMIC,
) as DynamicConfigFormValues,
initialValues,
onSubmit: readOnly ? () => undefined : toggle,
validationSchema: validationSchema[fidoConstants.VALIDATION_SCHEMAS.DYNAMIC_CONFIG],
enableReinitialize: true,
validateOnMount: true,
})

useEffect(() => {
if (fidoConfiguration) {
formik.resetForm({
values: transformToFormValues(
fidoConfiguration,
fidoConstants.DYNAMIC,
) as DynamicConfigFormValues,
})
}
}, [fidoConfiguration])

const submitForm = useCallback(
(userMessage: string) => {
if (readOnly) {
Expand All @@ -46,12 +59,8 @@ const DynamicConfiguration: React.FC<DynamicConfigurationProps> = ({
)

const handleCancel = useCallback(() => {
const initialValues = transformToFormValues(
fidoConfiguration,
fidoConstants.DYNAMIC,
) as DynamicConfigFormValues
formik.resetForm({ values: initialValues })
}, [formik, fidoConfiguration])
formik.resetForm()
}, [formik])

const handleFormSubmit = useCallback(
(e: React.FormEvent<HTMLFormElement>) => {
Expand Down
36 changes: 21 additions & 15 deletions admin-ui/plugins/fido/components/StaticConfiguration.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState, useCallback, useMemo } from 'react'
import React, { useState, useCallback, useEffect, useMemo } from 'react'
import { useFormik } from 'formik'
import { useTranslation } from 'react-i18next'

Expand Down Expand Up @@ -34,8 +34,6 @@ const StaticConfiguration: React.FC<StaticConfigurationProps> = ({
isSubmitting,
readOnly,
}) => {
const staticConfiguration = fidoConfiguration?.fido2Configuration

const { t } = useTranslation()

const [modal, setModal] = useState(false)
Expand All @@ -44,17 +42,29 @@ const StaticConfiguration: React.FC<StaticConfigurationProps> = ({
setModal((prev) => !prev)
}, [])

const initialValues: StaticConfigFormValues = transformToFormValues(
fidoConfiguration?.fido2Configuration,
fidoConstants.STATIC,
) as StaticConfigFormValues

const formik = useFormik<StaticConfigFormValues>({
initialValues: transformToFormValues(
staticConfiguration,
fidoConstants.STATIC,
) as StaticConfigFormValues,
initialValues,
onSubmit: readOnly ? () => undefined : toggle,
validationSchema: validationSchema[fidoConstants.VALIDATION_SCHEMAS.STATIC_CONFIG],
enableReinitialize: true,
validateOnMount: true,
})

useEffect(() => {
if (fidoConfiguration?.fido2Configuration) {
formik.resetForm({
values: transformToFormValues(
fidoConfiguration.fido2Configuration,
fidoConstants.STATIC,
) as StaticConfigFormValues,
})
}
}, [fidoConfiguration])

const submitForm = useCallback(
(userMessage: string) => {
if (readOnly) {
Expand All @@ -67,12 +77,8 @@ const StaticConfiguration: React.FC<StaticConfigurationProps> = ({
)

const handleCancel = useCallback(() => {
const initialValues = transformToFormValues(
staticConfiguration,
fidoConstants.STATIC,
) as StaticConfigFormValues
formik.resetForm({ values: initialValues })
}, [formik, staticConfiguration])
formik.resetForm()
}, [formik])

const requestedPartiesOptions = useMemo(() => {
return (formik.values.requestedParties || []).map((item) => ({
Expand Down Expand Up @@ -364,7 +370,7 @@ const StaticConfiguration: React.FC<StaticConfigurationProps> = ({
showError={!!(formik.errors.attestationMode && formik.touched.attestationMode)}
errorMessage={formik.errors.attestationMode}
handleChange={(_e) => {
formik.setFieldTouched(fidoConstants.FORM_FIELDS.ATTESTATION_MODE, true)
formik.setFieldTouched(fidoConstants.FORM_FIELDS.ATTESTATION_MODE, true, false)
}}
/>
</Col>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ const WebsiteSsoIdentityProviderForm = ({
}, [formik, initialValues])

const handleFormSubmit = useCallback(
(e: React.FormEvent<HTMLFormElement>) => {
async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault()
if (
!formik.values.metaDataFile &&
Expand All @@ -226,6 +226,17 @@ const WebsiteSsoIdentityProviderForm = ({
formik.setFieldTouched('metaDataFile', true)
return
}

const errors = await formik.validateForm()
if (Object.keys(errors).length > 0) {
const touched: Record<string, boolean> = {}
Object.keys(errors).forEach((key) => {
touched[key] = true
})
formik.setTouched(touched, false)
return
}

formik.handleSubmit(e)
},
[formik, configs?.idpMetaDataFN],
Expand Down Expand Up @@ -260,9 +271,14 @@ const WebsiteSsoIdentityProviderForm = ({
const error = formik.errors[fieldName]
const touched = formik.touched[fieldName]
const value = formik.values[fieldName]
return Boolean(error && (touched || (value !== undefined && value !== null && value !== '')))
return Boolean(
error &&
(touched ||
formik.submitCount > 0 ||
(value !== undefined && value !== null && String(value).length > 0)),
)
},
[formik.errors, formik.touched, formik.values],
[formik.errors, formik.touched, formik.values, formik.submitCount],
)

useEffect(() => {
Expand Down Expand Up @@ -394,7 +410,10 @@ const WebsiteSsoIdentityProviderForm = ({
required={!formik.values.metaDataFileImportedFlag}
lsize={4}
rsize={8}
showError={shouldShowError('idpEntityId')}
showError={Boolean(
formik.errors.idpEntityId &&
(formik.touched.idpEntityId || formik.submitCount > 0),
)}
errorMessage={formik.errors.idpEntityId}
disabled={viewOnly}
doc_category={DOC_SECTION}
Expand All @@ -411,7 +430,10 @@ const WebsiteSsoIdentityProviderForm = ({
lsize={4}
rsize={8}
required={!formik.values.metaDataFileImportedFlag}
showError={shouldShowError('nameIDPolicyFormat')}
showError={Boolean(
formik.errors.nameIDPolicyFormat &&
(formik.touched.nameIDPolicyFormat || formik.submitCount > 0),
)}
errorMessage={formik.errors.nameIDPolicyFormat}
disabled={viewOnly}
doc_category={DOC_SECTION}
Expand All @@ -427,7 +449,10 @@ const WebsiteSsoIdentityProviderForm = ({
formik={formik}
lsize={4}
rsize={8}
showError={shouldShowError('singleSignOnServiceUrl')}
showError={Boolean(
formik.errors.singleSignOnServiceUrl &&
(formik.touched.singleSignOnServiceUrl || formik.submitCount > 0),
)}
errorMessage={formik.errors.singleSignOnServiceUrl}
disabled={viewOnly}
doc_category={DOC_SECTION}
Expand All @@ -441,7 +466,10 @@ const WebsiteSsoIdentityProviderForm = ({
formik={formik}
lsize={4}
rsize={8}
showError={shouldShowError('singleLogoutServiceUrl')}
showError={Boolean(
formik.errors.singleLogoutServiceUrl &&
(formik.touched.singleLogoutServiceUrl || formik.submitCount > 0),
)}
errorMessage={formik.errors.singleLogoutServiceUrl}
disabled={viewOnly}
doc_category={DOC_SECTION}
Expand All @@ -456,7 +484,10 @@ const WebsiteSsoIdentityProviderForm = ({
lsize={4}
rsize={8}
type="textarea"
showError={shouldShowError('signingCertificate')}
showError={Boolean(
formik.errors.signingCertificate &&
(formik.touched.signingCertificate || formik.submitCount > 0),
)}
errorMessage={formik.errors.signingCertificate}
disabled={viewOnly}
rows={10}
Expand All @@ -472,7 +503,10 @@ const WebsiteSsoIdentityProviderForm = ({
lsize={4}
rsize={8}
type="textarea"
showError={shouldShowError('encryptionPublicKey')}
showError={Boolean(
formik.errors.encryptionPublicKey &&
(formik.touched.encryptionPublicKey || formik.submitCount > 0),
)}
errorMessage={formik.errors.encryptionPublicKey}
disabled={viewOnly}
rows={10}
Expand All @@ -487,7 +521,10 @@ const WebsiteSsoIdentityProviderForm = ({
formik={formik}
lsize={4}
rsize={8}
showError={shouldShowError('principalAttribute')}
showError={Boolean(
formik.errors.principalAttribute &&
(formik.touched.principalAttribute || formik.submitCount > 0),
)}
errorMessage={formik.errors.principalAttribute}
disabled={viewOnly}
doc_category={DOC_SECTION}
Expand All @@ -501,7 +538,10 @@ const WebsiteSsoIdentityProviderForm = ({
formik={formik}
lsize={4}
rsize={8}
showError={shouldShowError('principalType')}
showError={Boolean(
formik.errors.principalType &&
(formik.touched.principalType || formik.submitCount > 0),
)}
errorMessage={formik.errors.principalType}
disabled={viewOnly}
doc_category={DOC_SECTION}
Expand Down
Loading
Loading