From acf5001b37760a075e4876137ecde9cdcc1868fa Mon Sep 17 00:00:00 2001 From: Sylvain Date: Tue, 5 Apr 2022 16:56:44 +0200 Subject: [PATCH] (wip)(ui) data mapping configuration interface --- .../src/javascript/api/auth-provider.ts | 7 ++- .../data-mapping-form.tsx | 28 +++++++++ .../authentication-provider/oauth2-form.tsx | 57 +++++++++++++++++++ .../authentication-provider/provider-form.tsx | 11 ++++ .../components/form/form-select.tsx | 3 +- .../models/authentication-provider.ts | 9 ++- 6 files changed, 110 insertions(+), 5 deletions(-) create mode 100644 app/frontend/src/javascript/components/authentication-provider/data-mapping-form.tsx create mode 100644 app/frontend/src/javascript/components/authentication-provider/oauth2-form.tsx diff --git a/app/frontend/src/javascript/api/auth-provider.ts b/app/frontend/src/javascript/api/auth-provider.ts index ec00b2fbd..5fa49a262 100644 --- a/app/frontend/src/javascript/api/auth-provider.ts +++ b/app/frontend/src/javascript/api/auth-provider.ts @@ -1,4 +1,4 @@ -import { AuthenticationProvider } from '../models/authentication-provider'; +import { AuthenticationProvider, MappingFields } from '../models/authentication-provider'; import { AxiosResponse } from 'axios'; import apiClient from './clients/api-client'; @@ -27,5 +27,8 @@ export default class AuthProviderAPI { await apiClient.delete(`/api/auth_providers/${id}`); } - static async mappingFields(): Promise<> + static async mappingFields (): Promise { + const res: AxiosResponse = await apiClient.get('/api/auth_providers/mapping_fields'); + return res?.data; + } } diff --git a/app/frontend/src/javascript/components/authentication-provider/data-mapping-form.tsx b/app/frontend/src/javascript/components/authentication-provider/data-mapping-form.tsx new file mode 100644 index 000000000..2cff5b92a --- /dev/null +++ b/app/frontend/src/javascript/components/authentication-provider/data-mapping-form.tsx @@ -0,0 +1,28 @@ +import React, { useEffect } from 'react'; +import { UseFormRegister } from 'react-hook-form'; +import { FieldValues } from 'react-hook-form/dist/types/fields'; +import AuthProviderAPI from '../../api/auth-provider'; +import { MappingFields } from '../../models/authentication-provider'; +import { FormInput } from '../form/form-input'; + +export interface DataMappingFormProps { + register: UseFormRegister, +} + +export const DataMappingForm = ({ register }: DataMappingFormProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const [dataMapping, setDataMapping] = React.useState(null); + + // fetch the mapping data from the API on mount + useEffect(() => { + AuthProviderAPI.mappingFields().then((data) => { + setDataMapping(data); + }); + }, []); + + return ( +
+ +
+ ); +}; diff --git a/app/frontend/src/javascript/components/authentication-provider/oauth2-form.tsx b/app/frontend/src/javascript/components/authentication-provider/oauth2-form.tsx new file mode 100644 index 000000000..802f0c355 --- /dev/null +++ b/app/frontend/src/javascript/components/authentication-provider/oauth2-form.tsx @@ -0,0 +1,57 @@ +import React from 'react'; +import { FormInput } from '../form/form-input'; +import { UseFormRegister } from 'react-hook-form'; +import { FieldValues } from 'react-hook-form/dist/types/fields'; +import { useTranslation } from 'react-i18next'; + +interface Oauth2FormProps { + register: UseFormRegister, +} + +/** + * Partial form to fill the OAuth2 settings for a new/existing authentication provider. + */ +export const Oauth2Form = ({ register }: Oauth2FormProps) => { + const { t } = useTranslation('shared'); + + // regular expression to validate the the input fields + const endpointRegex = /^\/?([-._~:?#[\]@!$&'()*+,;=%\w]+\/?)*$/; + const urlRegex = /^(https?:\/\/)([\da-z.-]+)\.([-a-z0-9.]{2,30})([/\w .-]*)*\/?$/; + + return ( +
+
+ + + + + + + +
+ ); +}; diff --git a/app/frontend/src/javascript/components/authentication-provider/provider-form.tsx b/app/frontend/src/javascript/components/authentication-provider/provider-form.tsx index 14675b889..5c3ae02ea 100644 --- a/app/frontend/src/javascript/components/authentication-provider/provider-form.tsx +++ b/app/frontend/src/javascript/components/authentication-provider/provider-form.tsx @@ -7,6 +7,7 @@ import { IApplication } from '../../models/application'; import { FormInput } from '../form/form-input'; import { useTranslation } from 'react-i18next'; import { FormSelect } from '../form/form-select'; +import { Oauth2Form } from './oauth2-form'; declare const Application: IApplication; @@ -26,10 +27,16 @@ interface ProviderFormProps { type selectProvidableTypeOption = { value: string, label: string }; +/** + * Form to create or update an authentication provider. + */ export const ProviderForm: React.FC = ({ action, provider, onError, onSuccess }) => { const { handleSubmit, register, control } = useForm({ defaultValues: { ...provider } }); const { t } = useTranslation('shared'); + /** + * Callback triggered when the form is submitted: process with the provider creation or update. + */ const onSubmit: SubmitHandler = (data: AuthenticationProvider) => { if (data) { onSuccess('Provider created successfully'); @@ -38,6 +45,9 @@ export const ProviderForm: React.FC = ({ action, provider, on } }; + /** + * Build the list of available authentication methods to match with react-select requirements. + */ const buildProvidableTypeOptions = (): Array => { return Object.keys(METHODS).map((method: string) => { return { value: method, label: t(`app.shared.authentication.${METHODS[method]}`) }; @@ -48,6 +58,7 @@ export const ProviderForm: React.FC = ({ action, provider, on
+ {provider?.providable_type === 'OAuth2Provider' && } ); diff --git a/app/frontend/src/javascript/components/form/form-select.tsx b/app/frontend/src/javascript/components/form/form-select.tsx index 931f8c618..51dcbffe9 100644 --- a/app/frontend/src/javascript/components/form/form-select.tsx +++ b/app/frontend/src/javascript/components/form/form-select.tsx @@ -34,13 +34,12 @@ export const FormSelect =

{label}

} -
+
} control={control} defaultValue={valueDefault as UnpackNestedValue>>} render={({ field: { onChange, value, ref } }) =>