mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-02-27 21:54:27 +01:00
(wip)(ui) data mapping configuration interface
This commit is contained in:
parent
7beb1466bf
commit
acf5001b37
@ -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<MappingFields> {
|
||||
const res: AxiosResponse<MappingFields> = await apiClient.get('/api/auth_providers/mapping_fields');
|
||||
return res?.data;
|
||||
}
|
||||
}
|
||||
|
@ -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<TFieldValues> {
|
||||
register: UseFormRegister<TFieldValues>,
|
||||
}
|
||||
|
||||
export const DataMappingForm = <TFieldValues extends FieldValues>({ register }: DataMappingFormProps<TFieldValues>) => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const [dataMapping, setDataMapping] = React.useState<MappingFields>(null);
|
||||
|
||||
// fetch the mapping data from the API on mount
|
||||
useEffect(() => {
|
||||
AuthProviderAPI.mappingFields().then((data) => {
|
||||
setDataMapping(data);
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="data-mapping-form">
|
||||
<FormInput id="local_model" register={register} />
|
||||
</div>
|
||||
);
|
||||
};
|
@ -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<TFieldValues> {
|
||||
register: UseFormRegister<TFieldValues>,
|
||||
}
|
||||
|
||||
/**
|
||||
* Partial form to fill the OAuth2 settings for a new/existing authentication provider.
|
||||
*/
|
||||
export const Oauth2Form = <TFieldValues extends FieldValues>({ register }: Oauth2FormProps<TFieldValues>) => {
|
||||
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 (
|
||||
<div className="oauth2-form">
|
||||
<hr/>
|
||||
<FormInput id="base_url"
|
||||
register={register}
|
||||
placeholder="https://sso.example.net..."
|
||||
label={t('app.shared.oauth2.common_url')}
|
||||
rules={{ required: true, pattern: urlRegex }} />
|
||||
<FormInput id="authorization_endpoint"
|
||||
register={register}
|
||||
placeholder="/oauth2/auth..."
|
||||
label={t('app.shared.oauth2.authorization_endpoint')}
|
||||
rules={{ required: true, pattern: endpointRegex }} />
|
||||
<FormInput id="token_endpoint"
|
||||
register={register}
|
||||
placeholder="/oauth2/token..."
|
||||
label={t('app.shared.oauth2.token_acquisition_endpoint')}
|
||||
rules={{ required: true, pattern: endpointRegex }} />
|
||||
<FormInput id="profile_url"
|
||||
register={register}
|
||||
placeholder="https://exemple.net/user..."
|
||||
label={t('app.shared.oauth2.profil_edition_url')}
|
||||
rules={{ required: true, pattern: urlRegex }} />
|
||||
<FormInput id="client_id"
|
||||
register={register}
|
||||
label={t('app.shared.oauth2.client_identifier')}
|
||||
rules={{ required: true }} />
|
||||
<FormInput id="client_secret"
|
||||
register={register}
|
||||
label={t('app.shared.oauth2.client_secret')}
|
||||
rules={{ required: true }} />
|
||||
<FormInput id="scopes" register={register}
|
||||
placeholder="profile,email..."
|
||||
label={t('app.shared.oauth2.scopes')} />
|
||||
</div>
|
||||
);
|
||||
};
|
@ -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<ProviderFormProps> = ({ action, provider, onError, onSuccess }) => {
|
||||
const { handleSubmit, register, control } = useForm<AuthenticationProvider>({ defaultValues: { ...provider } });
|
||||
const { t } = useTranslation('shared');
|
||||
|
||||
/**
|
||||
* Callback triggered when the form is submitted: process with the provider creation or update.
|
||||
*/
|
||||
const onSubmit: SubmitHandler<AuthenticationProvider> = (data: AuthenticationProvider) => {
|
||||
if (data) {
|
||||
onSuccess('Provider created successfully');
|
||||
@ -38,6 +45,9 @@ export const ProviderForm: React.FC<ProviderFormProps> = ({ action, provider, on
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Build the list of available authentication methods to match with react-select requirements.
|
||||
*/
|
||||
const buildProvidableTypeOptions = (): Array<selectProvidableTypeOption> => {
|
||||
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<ProviderFormProps> = ({ action, provider, on
|
||||
<form className="provider-form" onSubmit={handleSubmit(onSubmit)}>
|
||||
<FormInput id="name" register={register} readOnly={action === 'update'} rules={{ required: true }} label={t('app.shared.authentication.name')} />
|
||||
<FormSelect id="providable_type" control={control} options={buildProvidableTypeOptions()} label={t('app.shared.authentication.authentication_type')} rules={{ required: true }} />
|
||||
{provider?.providable_type === 'OAuth2Provider' && <Oauth2Form register={register} />}
|
||||
<input type={'submit'} />
|
||||
</form>
|
||||
);
|
||||
|
@ -34,13 +34,12 @@ export const FormSelect = <TFieldValues extends FieldValues, TContext extends ob
|
||||
{label && <div className="form-select-header">
|
||||
<p>{label}</p>
|
||||
</div>}
|
||||
<div className="form-select-field">
|
||||
<div>
|
||||
<Controller name={id as FieldPath<TFieldValues>}
|
||||
control={control}
|
||||
defaultValue={valueDefault as UnpackNestedValue<FieldPathValue<TFieldValues, Path<TFieldValues>>>}
|
||||
render={({ field: { onChange, value, ref } }) =>
|
||||
<Select inputRef={ref}
|
||||
className="form-select-field-input"
|
||||
value={options.find(c => c.value === value)}
|
||||
onChange={val => onChange(val.value)}
|
||||
placeholder={placeholder}
|
||||
|
@ -8,6 +8,8 @@ export interface AuthenticationProvider {
|
||||
providable_attributes?: OAuth2Provider | OpenIdConnectProvider
|
||||
}
|
||||
|
||||
export type mappingType = 'string' | 'text' | 'date' | 'integer' | 'boolean';
|
||||
|
||||
export interface AuthenticationProviderMapping {
|
||||
id?: number,
|
||||
local_model: 'user' | 'profile',
|
||||
@ -16,7 +18,7 @@ export interface AuthenticationProviderMapping {
|
||||
api_endpoint: string,
|
||||
api_data_type: 'json',
|
||||
transformation: {
|
||||
type: 'string' | 'text' | 'date' | 'integer' | 'boolean',
|
||||
type: mappingType,
|
||||
format: 'iso8601' | 'rfc2822' | 'rfc3339' | 'timestamp-s' | 'timestamp-ms',
|
||||
true_value: string,
|
||||
false_value: string,
|
||||
@ -66,3 +68,8 @@ export interface OpenIdConnectProvider {
|
||||
client__end_session_endpoint?: string,
|
||||
profile_url?: string
|
||||
}
|
||||
|
||||
export interface MappingFields {
|
||||
user: Array<[string, mappingType]>,
|
||||
profile: Array<[string, mappingType]>
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user