mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2024-11-29 10:24:20 +01:00
(ui) improve the appeareance for the auth provider definition form
This commit is contained in:
parent
470a8284ff
commit
04ae91a7d1
@ -9,6 +9,9 @@ export interface BooleanMappingFormProps<TFieldValues> {
|
||||
fieldMappingId: number,
|
||||
}
|
||||
|
||||
/**
|
||||
* Partial form to map an internal boolean field to an external API providing a string value.
|
||||
*/
|
||||
export const BooleanMappingForm = <TFieldValues extends FieldValues>({ register, fieldMappingId }: BooleanMappingFormProps<TFieldValues>) => {
|
||||
const { t } = useTranslation('shared');
|
||||
|
||||
|
@ -17,6 +17,9 @@ export interface DataMappingFormProps<TFieldValues, TContext extends object> {
|
||||
|
||||
type selectModelFieldOption = { value: string, label: string };
|
||||
|
||||
/**
|
||||
* Partial form to define the mapping of the data between the API of the authentication provider and the application internals.
|
||||
*/
|
||||
export const DataMappingForm = <TFieldValues extends FieldValues, TContext extends object>({ register, control }: DataMappingFormProps<TFieldValues, TContext>) => {
|
||||
const { t } = useTranslation('shared');
|
||||
const [dataMapping, setDataMapping] = useState<MappingFields>(null);
|
||||
@ -91,11 +94,13 @@ export const DataMappingForm = <TFieldValues extends FieldValues, TContext exten
|
||||
return (
|
||||
<div className="data-mapping-form array-mapping-form">
|
||||
<h4>{t('app.shared.oauth2.define_the_fields_mapping')}</h4>
|
||||
<FabButton
|
||||
icon={<i className="fa fa-plus"/>}
|
||||
onClick={() => append({})}>
|
||||
{t('app.shared.oauth2.add_a_match')}
|
||||
</FabButton>
|
||||
<div className="mapping-actions">
|
||||
<FabButton
|
||||
icon={<i className="fa fa-plus"/>}
|
||||
onClick={() => append({})}>
|
||||
{t('app.shared.oauth2.add_a_match')}
|
||||
</FabButton>
|
||||
</div>
|
||||
{fields.map((item, index) => (
|
||||
<div key={item.id} className="mapping-item">
|
||||
<div className="inputs">
|
||||
@ -128,7 +133,7 @@ export const DataMappingForm = <TFieldValues extends FieldValues, TContext exten
|
||||
</div>
|
||||
</div>
|
||||
<div className="actions">
|
||||
<FabButton icon={<i className="fa fa-random" />} onClick={toggleTypeMappingModal} disabled={getField(output, index) === undefined} />
|
||||
<FabButton icon={<i className="fa fa-random" />} onClick={toggleTypeMappingModal} disabled={getField(output, index) === undefined} tooltip={t('app.shared.authentication.data_mapping')} />
|
||||
<FabButton icon={<i className="fa fa-trash" />} onClick={() => remove(index)} className="delete-button" />
|
||||
<TypeMappingModal model={getModel(output, index)}
|
||||
field={getField(output, index)}
|
||||
|
@ -9,6 +9,9 @@ export interface DateMappingFormProps<TFieldValues, TContext extends object> {
|
||||
fieldMappingId: number,
|
||||
}
|
||||
|
||||
/**
|
||||
* Partial form for mapping an internal date field to an external API.
|
||||
*/
|
||||
export const DateMappingForm = <TFieldValues extends FieldValues, TContext extends object>({ control, fieldMappingId }: DateMappingFormProps<TFieldValues, TContext>) => {
|
||||
const { t } = useTranslation('shared');
|
||||
|
||||
|
@ -12,6 +12,9 @@ export interface IntegerMappingFormProps<TFieldValues, TContext extends object>
|
||||
fieldMappingId: number,
|
||||
}
|
||||
|
||||
/**
|
||||
* Partial for to map an internal integer field to an external API providing a string value.
|
||||
*/
|
||||
export const IntegerMappingForm = <TFieldValues extends FieldValues, TContext extends object>({ register, control, fieldMappingId }: IntegerMappingFormProps<TFieldValues, TContext>) => {
|
||||
const { t } = useTranslation('shared');
|
||||
|
||||
@ -20,9 +23,11 @@ export const IntegerMappingForm = <TFieldValues extends FieldValues, TContext ex
|
||||
return (
|
||||
<div className="integer-mapping-form array-mapping-form">
|
||||
<h4>{t('app.shared.authentication.mappings')}</h4>
|
||||
<FabButton
|
||||
icon={<i className="fa fa-plus" />}
|
||||
onClick={() => append({})} />
|
||||
<div className="mapping-actions">
|
||||
<FabButton
|
||||
icon={<i className="fa fa-plus" />}
|
||||
onClick={() => append({})} />
|
||||
</div>
|
||||
{fields.map((item, index) => (
|
||||
<div key={item.id} className="mapping-item">
|
||||
<div className="inputs">
|
||||
|
@ -9,6 +9,7 @@ import { useTranslation } from 'react-i18next';
|
||||
import { FormSelect } from '../form/form-select';
|
||||
import { Oauth2Form } from './oauth2-form';
|
||||
import { DataMappingForm } from './data-mapping-form';
|
||||
import { FabButton } from '../base/fab-button';
|
||||
|
||||
declare const Application: IApplication;
|
||||
|
||||
@ -79,7 +80,9 @@ export const ProviderForm: React.FC<ProviderFormProps> = ({ action, provider, on
|
||||
rules={{ required: true }} />
|
||||
{providableType === 'OAuth2Provider' && <Oauth2Form register={register} />}
|
||||
{providableType && providableType !== 'DatabaseProvider' && <DataMappingForm register={register} control={control} />}
|
||||
<input type={'submit'} />
|
||||
<div className="main-actions">
|
||||
<FabButton type="submit" className="submit-button">{t('app.shared.authentication.save')}</FabButton>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
@ -12,6 +12,9 @@ export interface StringMappingFormProps<TFieldValues, TContext extends object> {
|
||||
fieldMappingId: number,
|
||||
}
|
||||
|
||||
/**
|
||||
* Partial form to map an internal string field to an external API.
|
||||
*/
|
||||
export const StringMappingForm = <TFieldValues extends FieldValues, TContext extends object>({ register, control, fieldMappingId }: StringMappingFormProps<TFieldValues, TContext>) => {
|
||||
const { t } = useTranslation('shared');
|
||||
|
||||
@ -20,9 +23,11 @@ export const StringMappingForm = <TFieldValues extends FieldValues, TContext ext
|
||||
return (
|
||||
<div className="string-mapping-form array-mapping-form">
|
||||
<h4>{t('app.shared.authentication.mappings')}</h4>
|
||||
<FabButton
|
||||
icon={<i className="fa fa-plus" />}
|
||||
onClick={() => append({})} />
|
||||
<div className="mapping-actions">
|
||||
<FabButton
|
||||
icon={<i className="fa fa-plus" />}
|
||||
onClick={() => append({})} />
|
||||
</div>
|
||||
{fields.map((item, index) => (
|
||||
<div key={item.id} className="mapping-item">
|
||||
<div className="inputs">
|
||||
|
@ -21,12 +21,19 @@ interface TypeMappingModalProps<TFieldValues, TContext extends object> {
|
||||
fieldMappingId: number,
|
||||
}
|
||||
|
||||
/**
|
||||
* Modal dialog to display the expected type for the current data field.
|
||||
* Also allows to map the incoming data (from the authentication provider API) to the expected type/data.
|
||||
*
|
||||
* This component is intended to be used in a react-hook-form context.
|
||||
*/
|
||||
export const TypeMappingModal = <TFieldValues extends FieldValues, TContext extends object>({ model, field, type, isOpen, toggleModal, register, control, fieldMappingId }:TypeMappingModalProps<TFieldValues, TContext>) => {
|
||||
const { t } = useTranslation('shared');
|
||||
|
||||
return (
|
||||
<FabModal isOpen={isOpen}
|
||||
toggleModal={toggleModal}
|
||||
className="type-mapping-modal"
|
||||
title={t('app.shared.authentication.data_mapping')}
|
||||
confirmButton={<i className="fa fa-check" />}
|
||||
onConfirm={toggleModal}>
|
||||
|
@ -7,12 +7,13 @@ interface FabButtonProps {
|
||||
disabled?: boolean,
|
||||
type?: 'submit' | 'reset' | 'button',
|
||||
form?: string,
|
||||
tooltip?: string,
|
||||
}
|
||||
|
||||
/**
|
||||
* This component is a template for a clickable button that wraps the application style
|
||||
*/
|
||||
export const FabButton: React.FC<FabButtonProps> = ({ onClick, icon, className, disabled, type, form, children }) => {
|
||||
export const FabButton: React.FC<FabButtonProps> = ({ onClick, icon, className, disabled, type, form, tooltip, children }) => {
|
||||
/**
|
||||
* Check if the current component was provided an icon to display
|
||||
*/
|
||||
@ -37,7 +38,7 @@ export const FabButton: React.FC<FabButtonProps> = ({ onClick, icon, className,
|
||||
};
|
||||
|
||||
return (
|
||||
<button type={type} form={form} onClick={handleClick} disabled={disabled} className={`fab-button ${className || ''}`}>
|
||||
<button type={type} form={form} onClick={handleClick} disabled={disabled} className={`fab-button ${className || ''}`} title={tooltip}>
|
||||
{hasIcon() && <span className={hasChildren() ? 'fab-button--icon' : 'fab-button--icon-only'}>{icon}</span>}
|
||||
{children}
|
||||
</button>
|
||||
|
@ -17,6 +17,8 @@
|
||||
|
||||
@import "modules/authentication-provider/data-mapping-form";
|
||||
@import "modules/authentication-provider/array-mapping-form";
|
||||
@import "modules/authentication-provider/provider-form";
|
||||
@import "modules/authentication-provider/type-mapping-modal";
|
||||
@import "modules/base/fab-alert";
|
||||
@import "modules/base/fab-button";
|
||||
@import "modules/base/fab-input";
|
||||
|
@ -1,9 +1,14 @@
|
||||
.array-mapping-form {
|
||||
.mapping-actions {
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
margin-right: 1rem;
|
||||
}
|
||||
.mapping-item {
|
||||
margin: 1rem;
|
||||
border-left: 4px solid var(--gray-soft-dark);
|
||||
border-radius: 4px;
|
||||
padding-left: 1em;
|
||||
margin: 1rem 1rem 2rem;
|
||||
border: 1px solid var(--gray-soft-dark);
|
||||
border-radius: 8px;
|
||||
padding: 1em;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
@ -1,6 +1,9 @@
|
||||
.data-mapping-form {
|
||||
.mapping-item .inputs .form-item {
|
||||
margin-left: 20px;
|
||||
}
|
||||
.local-data,
|
||||
.remote-data{
|
||||
.remote-data {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
@ -0,0 +1,20 @@
|
||||
|
||||
.provider-form {
|
||||
.main-actions {
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
|
||||
.submit-button {
|
||||
margin-top: 2em;
|
||||
border-color: var(--information-light);
|
||||
background-color: var(--information);
|
||||
color: white;
|
||||
|
||||
&:hover {
|
||||
border-color: var(--information);
|
||||
background-color: var(--information-dark);
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
.type-mapping-modal {
|
||||
.fab-modal-footer {
|
||||
.modal-btn--confirm {
|
||||
border-color: var(--information-light);
|
||||
background-color: var(--information);
|
||||
color: white;
|
||||
|
||||
&:hover {
|
||||
border-color: var(--information);
|
||||
background-color: var(--information-dark);
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -31,23 +31,14 @@
|
||||
<div class="row no-gutter">
|
||||
<div class=" col-sm-12 col-md-9 b-r nopadding">
|
||||
|
||||
<form role="form" name="providerForm" class="form-horizontal" novalidate>
|
||||
|
||||
<section class="panel panel-default bg-light m-lg">
|
||||
<div class="panel-body m-r">
|
||||
<section class="panel panel-default bg-light m-lg">
|
||||
<div class="panel-body m-r">
|
||||
|
||||
<provider-form action="'create'" on-success="onSuccess" on-error="onError"></provider-form>
|
||||
<provider-form action="'create'" on-success="onSuccess" on-error="onError"></provider-form>
|
||||
|
||||
<ng-include src="'/admin/authentications/_form.html'"></ng-include>
|
||||
<ng-include src="'/admin/authentications/_oauth2.html'" ng-if="provider.providable_type == 'OAuth2Provider'"></ng-include>
|
||||
</div> <!-- ./panel-body -->
|
||||
|
||||
|
||||
<div class="panel-footer no-padder">
|
||||
<input type="button" value="{{ 'app.shared.buttons.save' | translate }}" class="r-b btn-valid btn btn-warning btn-block p-lg btn-lg text-u-c" ng-disabled="providerForm.$invalid" ng-click="registerProvider()"/>
|
||||
</div>
|
||||
</section>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
@ -265,6 +265,7 @@ en:
|
||||
true_value: "True value"
|
||||
false_value: "False value"
|
||||
date_format: "Date format"
|
||||
save: "Save"
|
||||
types:
|
||||
integer: "integer"
|
||||
string: "string"
|
||||
|
Loading…
Reference in New Issue
Block a user