fix forms
This commit is contained in:
@@ -48,6 +48,7 @@ const Check = ({ onSubmit }: Props) => {
|
||||
<Input
|
||||
{...field}
|
||||
type="text"
|
||||
data-testid="check_domain_name"
|
||||
placeholder={t('form_enter_host')}
|
||||
error={fieldState.error?.message}
|
||||
rightAddon={
|
||||
@@ -55,6 +56,7 @@ const Check = ({ onSubmit }: Props) => {
|
||||
<button
|
||||
className="btn btn-success btn-standard btn-large"
|
||||
type="submit"
|
||||
data-testid="check_domain_submit"
|
||||
disabled={!isDirty || !isValid || processingCheck}>
|
||||
{t('check')}
|
||||
</button>
|
||||
|
||||
@@ -74,7 +74,12 @@ export const FiltersList = ({ categories, filters, selectedSources }: Props) =>
|
||||
name={id}
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Checkbox {...field} title={name} disabled={isSelected} />
|
||||
<Checkbox
|
||||
{...field}
|
||||
data-testid={`filters_${id}`}
|
||||
title={name}
|
||||
disabled={isSelected}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{renderIcons(iconsData)}
|
||||
|
||||
@@ -15,13 +15,13 @@ type FormValues = {
|
||||
};
|
||||
|
||||
type Props = {
|
||||
closeModal: (...args: unknown[]) => void;
|
||||
closeModal: () => void;
|
||||
onSubmit: (values: FormValues) => void;
|
||||
processingAddFilter: boolean;
|
||||
processingConfigFilter: boolean;
|
||||
whitelist?: boolean;
|
||||
modalType: string;
|
||||
toggleFilteringModal: (...args: unknown[]) => void;
|
||||
toggleFilteringModal: ({ type }: { type?: keyof typeof MODAL_TYPE }) => void;
|
||||
selectedSources?: Record<string, boolean>;
|
||||
initialValues?: FormValues;
|
||||
};
|
||||
@@ -42,14 +42,14 @@ export const Form = ({
|
||||
const methods = useForm({ defaultValues: initialValues });
|
||||
const { handleSubmit, control } = methods;
|
||||
|
||||
const openModal = (modalType: any, timeout = MODAL_OPEN_TIMEOUT) => {
|
||||
toggleFilteringModal();
|
||||
const openModal = (modalType: keyof typeof MODAL_TYPE, timeout = MODAL_OPEN_TIMEOUT) => {
|
||||
toggleFilteringModal(undefined);
|
||||
setTimeout(() => toggleFilteringModal({ type: modalType }), timeout);
|
||||
};
|
||||
|
||||
const openFilteringListModal = () => openModal(MODAL_TYPE.CHOOSE_FILTERING_LIST);
|
||||
const openFilteringListModal = () => openModal('CHOOSE_FILTERING_LIST');
|
||||
|
||||
const openAddFiltersModal = () => openModal(MODAL_TYPE.ADD_FILTERS);
|
||||
const openAddFiltersModal = () => openModal('ADD_FILTERS');
|
||||
|
||||
return (
|
||||
<FormProvider {...methods}>
|
||||
@@ -81,8 +81,15 @@ export const Form = ({
|
||||
<Controller
|
||||
name="name"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Input {...field} type="text" placeholder={t('enter_name_hint')} trimOnBlur />
|
||||
render={({ field, fieldState }) => (
|
||||
<Input
|
||||
{...field}
|
||||
type="text"
|
||||
data-testid="filters_name"
|
||||
placeholder={t('enter_name_hint')}
|
||||
error={fieldState.error?.message}
|
||||
trimOnBlur
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
@@ -92,11 +99,13 @@ export const Form = ({
|
||||
name="url"
|
||||
control={control}
|
||||
rules={{ validate: { validateRequiredValue, validatePath } }}
|
||||
render={({ field }) => (
|
||||
render={({ field, fieldState }) => (
|
||||
<Input
|
||||
{...field}
|
||||
type="text"
|
||||
data-testid="filters_url"
|
||||
placeholder={t('enter_url_or_path_hint')}
|
||||
error={fieldState.error?.message}
|
||||
trimOnBlur
|
||||
/>
|
||||
)}
|
||||
@@ -118,6 +127,7 @@ export const Form = ({
|
||||
{modalType !== MODAL_TYPE.SELECT_MODAL_TYPE && (
|
||||
<button
|
||||
type="submit"
|
||||
data-testid="filters_save"
|
||||
className="btn btn-success"
|
||||
disabled={processingAddFilter || processingConfigFilter}>
|
||||
{t('save_btn')}
|
||||
|
||||
@@ -5,16 +5,16 @@ import { Trans, useTranslation } from 'react-i18next';
|
||||
import { validateAnswer, validateDomain, validateRequiredValue } from '../../../helpers/validators';
|
||||
import { Input } from '../../ui/Controls/Input';
|
||||
|
||||
interface FormValues {
|
||||
interface RewriteFormValues {
|
||||
domain: string;
|
||||
answer: string;
|
||||
}
|
||||
|
||||
type Props = {
|
||||
processingAdd: boolean;
|
||||
currentRewrite?: { answer: string; domain: string };
|
||||
currentRewrite?: RewriteFormValues;
|
||||
toggleRewritesModal: () => void;
|
||||
onSubmit?: (data: FormValues) => Promise<void> | void;
|
||||
onSubmit?: (data: RewriteFormValues) => Promise<void> | void;
|
||||
};
|
||||
|
||||
const Form = ({ processingAdd, currentRewrite, toggleRewritesModal, onSubmit }: Props) => {
|
||||
@@ -25,7 +25,7 @@ const Form = ({ processingAdd, currentRewrite, toggleRewritesModal, onSubmit }:
|
||||
reset,
|
||||
control,
|
||||
formState: { isDirty, isSubmitting },
|
||||
} = useForm<FormValues>({
|
||||
} = useForm<RewriteFormValues>({
|
||||
mode: 'onBlur',
|
||||
defaultValues: {
|
||||
domain: currentRewrite?.domain || '',
|
||||
@@ -33,7 +33,7 @@ const Form = ({ processingAdd, currentRewrite, toggleRewritesModal, onSubmit }:
|
||||
},
|
||||
});
|
||||
|
||||
const handleFormSubmit = async (data: FormValues) => {
|
||||
const handleFormSubmit = async (data: RewriteFormValues) => {
|
||||
if (onSubmit) {
|
||||
await onSubmit(data);
|
||||
}
|
||||
@@ -59,6 +59,7 @@ const Form = ({ processingAdd, currentRewrite, toggleRewritesModal, onSubmit }:
|
||||
<Input
|
||||
{...field}
|
||||
type="text"
|
||||
data-testid="rewrites_domain"
|
||||
placeholder={t('form_domain')}
|
||||
error={fieldState.error?.message}
|
||||
/>
|
||||
@@ -91,6 +92,7 @@ const Form = ({ processingAdd, currentRewrite, toggleRewritesModal, onSubmit }:
|
||||
<Input
|
||||
{...field}
|
||||
type="text"
|
||||
data-testid="rewrites_answer"
|
||||
placeholder={t('form_answer')}
|
||||
error={fieldState.error?.message}
|
||||
/>
|
||||
@@ -111,6 +113,7 @@ const Form = ({ processingAdd, currentRewrite, toggleRewritesModal, onSubmit }:
|
||||
<div className="btn-list">
|
||||
<button
|
||||
type="button"
|
||||
data-testid="rewrites_cancel"
|
||||
className="btn btn-secondary btn-standard"
|
||||
disabled={isSubmitting || processingAdd}
|
||||
onClick={() => {
|
||||
@@ -122,6 +125,7 @@ const Form = ({ processingAdd, currentRewrite, toggleRewritesModal, onSubmit }:
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
data-testid="rewrites_save"
|
||||
className="btn btn-success btn-standard"
|
||||
disabled={isSubmitting || !isDirty || processingAdd}>
|
||||
<Trans>save_btn</Trans>
|
||||
|
||||
@@ -46,6 +46,7 @@ export const Form = ({ initialValues, blockedServices, processing, processingSet
|
||||
<div className="col-6">
|
||||
<button
|
||||
type="button"
|
||||
data-testid="blocked_services_block_all"
|
||||
className="btn btn-secondary btn-block"
|
||||
disabled={processing || processingSet}
|
||||
onClick={() => handleToggleAllServices(true)}>
|
||||
@@ -56,6 +57,7 @@ export const Form = ({ initialValues, blockedServices, processing, processingSet
|
||||
<div className="col-6">
|
||||
<button
|
||||
type="button"
|
||||
data-testid="blocked_services_unblock_all"
|
||||
className="btn btn-secondary btn-block"
|
||||
disabled={processing || processingSet}
|
||||
onClick={() => handleToggleAllServices(false)}>
|
||||
@@ -65,7 +67,7 @@ export const Form = ({ initialValues, blockedServices, processing, processingSet
|
||||
</div>
|
||||
|
||||
<div className="services">
|
||||
{blockedServices.map((service: any) => (
|
||||
{blockedServices.map((service: BlockedService) => (
|
||||
<Controller
|
||||
key={service.id}
|
||||
name={`blocked_services.${service.id}`}
|
||||
@@ -73,6 +75,7 @@ export const Form = ({ initialValues, blockedServices, processing, processingSet
|
||||
render={({ field }) => (
|
||||
<ServiceField
|
||||
{...field}
|
||||
data-testid={`blocked_services_${service.id}`}
|
||||
placeholder={service.name}
|
||||
disabled={processing || processingSet}
|
||||
icon={service.icon_svg}
|
||||
@@ -86,6 +89,7 @@ export const Form = ({ initialValues, blockedServices, processing, processingSet
|
||||
<div className="btn-list">
|
||||
<button
|
||||
type="submit"
|
||||
data-testid="blocked_services_save"
|
||||
className="btn btn-success btn-standard btn-large"
|
||||
disabled={isSubmitting || !isDirty || processing || processingSet}>
|
||||
<Trans>save_btn</Trans>
|
||||
|
||||
@@ -11,7 +11,7 @@ type Props = ControllerRenderProps<FieldValues> & {
|
||||
};
|
||||
|
||||
export const ServiceField = React.forwardRef<HTMLInputElement, Props>(
|
||||
({ name, value, onChange, onBlur, placeholder, disabled, className, icon, error }, ref) => (
|
||||
({ name, value, onChange, onBlur, placeholder, disabled, className, icon, error, ...rest }, ref) => (
|
||||
<>
|
||||
<label className={cn('service custom-switch', className)}>
|
||||
<input
|
||||
@@ -23,6 +23,7 @@ export const ServiceField = React.forwardRef<HTMLInputElement, Props>(
|
||||
onBlur={onBlur}
|
||||
ref={ref}
|
||||
disabled={disabled}
|
||||
{...rest}
|
||||
/>
|
||||
|
||||
<span className="service__switch custom-switch-indicator"></span>
|
||||
|
||||
@@ -28,6 +28,7 @@ export const BlockedServices = ({ services }: Props) => {
|
||||
render={({ field }) => (
|
||||
<ServiceField
|
||||
{...field}
|
||||
data-testid="clients_use_global_blocked_services"
|
||||
placeholder={t('blocked_services_global')}
|
||||
className="service--global"
|
||||
/>
|
||||
@@ -38,6 +39,7 @@ export const BlockedServices = ({ services }: Props) => {
|
||||
<div className="col-6">
|
||||
<button
|
||||
type="button"
|
||||
data-testid="clients_block_all"
|
||||
className="btn btn-secondary btn-block"
|
||||
disabled={useGlobalServices}
|
||||
onClick={() => handleToggleAllServices(true)}>
|
||||
@@ -48,6 +50,7 @@ export const BlockedServices = ({ services }: Props) => {
|
||||
<div className="col-6">
|
||||
<button
|
||||
type="button"
|
||||
data-testid="clients_unblock_all"
|
||||
className="btn btn-secondary btn-block"
|
||||
disabled={useGlobalServices}
|
||||
onClick={() => handleToggleAllServices(false)}>
|
||||
@@ -65,6 +68,7 @@ export const BlockedServices = ({ services }: Props) => {
|
||||
render={({ field }) => (
|
||||
<ServiceField
|
||||
{...field}
|
||||
data-testid={`clients_service_${service.id}`}
|
||||
placeholder={service.name}
|
||||
disabled={useGlobalServices}
|
||||
icon={service.icon_svg}
|
||||
|
||||
@@ -31,6 +31,7 @@ export const ClientIds = () => {
|
||||
<Input
|
||||
{...field}
|
||||
type="text"
|
||||
data-testid={`clients_id_${index}`}
|
||||
placeholder={t('form_enter_id')}
|
||||
error={fieldState.error?.message}
|
||||
onBlur={(event) => {
|
||||
@@ -43,6 +44,7 @@ export const ClientIds = () => {
|
||||
<span className="input-group-append">
|
||||
<button
|
||||
type="button"
|
||||
data-testid={`clients_id_remove_${index}`}
|
||||
className="btn btn-secondary btn-icon btn-icon--green"
|
||||
onClick={() => remove(index)}>
|
||||
<svg className="icon icon--24">
|
||||
@@ -59,6 +61,7 @@ export const ClientIds = () => {
|
||||
))}
|
||||
<button
|
||||
type="button"
|
||||
data-testid="clients_id_add"
|
||||
className="btn btn-link btn-block btn-sm"
|
||||
onClick={() => append({ name: '' })}
|
||||
title={t('form_add_id')}>
|
||||
|
||||
@@ -64,6 +64,7 @@ export const MainSettings = ({ safeSearchServices }: Props) => {
|
||||
render={({ field }) => (
|
||||
<Checkbox
|
||||
{...field}
|
||||
data-testid={`clients_${setting.name}`}
|
||||
title={setting.placeholder}
|
||||
disabled={setting.name !== 'use_global_settings' ? useGlobalSettings : false}
|
||||
/>
|
||||
@@ -77,7 +78,12 @@ export const MainSettings = ({ safeSearchServices }: Props) => {
|
||||
name="safe_search.enabled"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Checkbox {...field} title={t('enforce_safe_search')} disabled={useGlobalSettings} />
|
||||
<Checkbox
|
||||
data-testid="clients_safe_search"
|
||||
{...field}
|
||||
title={t('enforce_safe_search')}
|
||||
disabled={useGlobalSettings}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
@@ -89,7 +95,12 @@ export const MainSettings = ({ safeSearchServices }: Props) => {
|
||||
name={`safe_search.${searchKey}`}
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Checkbox {...field} title={captitalizeWords(searchKey)} disabled={useGlobalSettings} />
|
||||
<Checkbox
|
||||
{...field}
|
||||
data-testid={`clients_safe_search_${searchKey}`}
|
||||
title={captitalizeWords(searchKey)}
|
||||
disabled={useGlobalSettings}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
@@ -104,7 +115,9 @@ export const MainSettings = ({ safeSearchServices }: Props) => {
|
||||
<Controller
|
||||
name={setting.name}
|
||||
control={control}
|
||||
render={({ field }) => <Checkbox {...field} title={setting.placeholder} />}
|
||||
render={({ field }) => (
|
||||
<Checkbox {...field} data-testid={`clients_${setting.name}`} title={setting.placeholder} />
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -8,7 +8,7 @@ import { Textarea } from '../../../../ui/Controls/Textarea';
|
||||
import { ClientForm } from '../types';
|
||||
import { Checkbox } from '../../../../ui/Controls/Checkbox';
|
||||
import { Input } from '../../../../ui/Controls/Input';
|
||||
import { trimLinesAndRemoveEmpty } from '../../../../../helpers/helpers';
|
||||
import { toNumber } from '../../../../../helpers/form';
|
||||
|
||||
export const UpstreamDns = () => {
|
||||
const { t } = useTranslation();
|
||||
@@ -18,14 +18,7 @@ export const UpstreamDns = () => {
|
||||
return (
|
||||
<div title={t('upstream_dns')}>
|
||||
<div className="form__desc mb-3">
|
||||
<Trans
|
||||
components={[
|
||||
<a href="#dns" key="0">
|
||||
link
|
||||
</a>,
|
||||
]}>
|
||||
upstream_dns_client_desc
|
||||
</Trans>
|
||||
<Trans components={[<a href="#dns" key="0" />]}>upstream_dns_client_desc</Trans>
|
||||
</div>
|
||||
|
||||
<Controller
|
||||
@@ -34,13 +27,10 @@ export const UpstreamDns = () => {
|
||||
render={({ field }) => (
|
||||
<Textarea
|
||||
{...field}
|
||||
data-testid="clients_upstreams"
|
||||
className="form-control form-control--textarea mb-5"
|
||||
placeholder={t('upstream_dns')}
|
||||
onBlur={(event) => {
|
||||
const normalizedValue = trimLinesAndRemoveEmpty(event.target.value);
|
||||
field.onBlur();
|
||||
field.onChange(normalizedValue);
|
||||
}}
|
||||
trimOnBlur
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
@@ -53,7 +43,13 @@ export const UpstreamDns = () => {
|
||||
<Controller
|
||||
name="upstreams_cache_enabled"
|
||||
control={control}
|
||||
render={({ field }) => <Checkbox {...field} title={t('enable_upstream_dns_cache')} />}
|
||||
render={({ field }) => (
|
||||
<Checkbox
|
||||
{...field}
|
||||
data-testid="clients_upstreams_cache_enabled"
|
||||
title={t('enable_upstream_dns_cache')}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -69,10 +65,15 @@ export const UpstreamDns = () => {
|
||||
<Input
|
||||
{...field}
|
||||
type="number"
|
||||
data-testid="clients_upstreams_cache_size"
|
||||
placeholder={t('enter_cache_size')}
|
||||
error={fieldState.error?.message}
|
||||
min={0}
|
||||
max={UINT32_RANGE.MAX}
|
||||
onChange={(e) => {
|
||||
const { value } = e.target;
|
||||
field.onChange(toNumber(value));
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
||||
@@ -70,7 +70,6 @@ export const Form = ({
|
||||
handleSubmit,
|
||||
reset,
|
||||
control,
|
||||
setValue,
|
||||
formState: { isSubmitting, isValid },
|
||||
} = methods;
|
||||
|
||||
@@ -116,6 +115,7 @@ export const Form = ({
|
||||
<Input
|
||||
{...field}
|
||||
type="text"
|
||||
data-testid="clients_name"
|
||||
placeholder={t('form_client_name')}
|
||||
error={fieldState.error?.message}
|
||||
onBlur={(event) => {
|
||||
@@ -155,13 +155,11 @@ export const Form = ({
|
||||
render={({ field }) => (
|
||||
<Select
|
||||
{...field}
|
||||
data-testid="clients_tags"
|
||||
options={tagsOptions}
|
||||
className="basic-multi-select"
|
||||
classNamePrefix="select"
|
||||
isMulti
|
||||
onChange={(selectedOptions) => {
|
||||
setValue('tags', selectedOptions);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
||||
@@ -27,6 +27,7 @@ import { Radio } from '../../ui/Controls/Radio';
|
||||
import { Input } from '../../ui/Controls/Input';
|
||||
import { Textarea } from '../../ui/Controls/Textarea';
|
||||
import { EncryptionData } from '../../../initialState';
|
||||
import { toNumber } from '../../../helpers/form';
|
||||
|
||||
const certificateSourceOptions = [
|
||||
{
|
||||
@@ -335,6 +336,10 @@ export const Form = ({
|
||||
placeholder={t('encryption_https')}
|
||||
error={fieldState.error?.message}
|
||||
disabled={!isEnabled}
|
||||
onChange={(e) => {
|
||||
const { value } = e.target;
|
||||
field.onChange(toNumber(value));
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
@@ -362,6 +367,10 @@ export const Form = ({
|
||||
placeholder={t('encryption_dot')}
|
||||
error={fieldState.error?.message}
|
||||
disabled={!isEnabled}
|
||||
onChange={(e) => {
|
||||
const { value } = e.target;
|
||||
field.onChange(toNumber(value));
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
@@ -389,6 +398,10 @@ export const Form = ({
|
||||
placeholder={t('encryption_doq')}
|
||||
error={fieldState.error?.message}
|
||||
disabled={!isEnabled}
|
||||
onChange={(e) => {
|
||||
const { value } = e.target;
|
||||
field.onChange(toNumber(value));
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
||||
@@ -5,7 +5,6 @@ import i18next from 'i18next';
|
||||
import { Controller, useForm } from 'react-hook-form';
|
||||
import { STATS_INTERVALS_DAYS, DAY, RETENTION_CUSTOM, RETENTION_RANGE } from '../../../helpers/constants';
|
||||
|
||||
import { trimLinesAndRemoveEmpty } from '../../../helpers/helpers';
|
||||
import '../FormButton.css';
|
||||
import { Checkbox } from '../../ui/Controls/Checkbox';
|
||||
import { Input } from '../../ui/Controls/Input';
|
||||
@@ -75,11 +74,6 @@ export const Form = ({ initialValues, processing, processingReset, onSubmit, onR
|
||||
onSubmit(data);
|
||||
};
|
||||
|
||||
const handleIgnoredBlur = (e: React.FocusEvent<HTMLTextAreaElement>) => {
|
||||
const trimmed = trimLinesAndRemoveEmpty(e.target.value);
|
||||
setValue('ignored', trimmed);
|
||||
};
|
||||
|
||||
const disableSubmit = isSubmitting || processing || (intervalValue === RETENTION_CUSTOM && !customIntervalValue);
|
||||
|
||||
return (
|
||||
@@ -179,7 +173,7 @@ export const Form = ({ initialValues, processing, processingReset, onSubmit, onR
|
||||
className="text-input"
|
||||
disabled={processing}
|
||||
error={fieldState.error?.message}
|
||||
onBlur={handleIgnoredBlur}
|
||||
trimOnBlur
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
||||
@@ -15,7 +15,7 @@ type Props = {
|
||||
};
|
||||
|
||||
export const Checkbox = forwardRef<HTMLInputElement, Props>(
|
||||
({ title, subtitle, value, name, disabled, error, className = 'checkbox--form', onChange }, ref) => (
|
||||
({ title, subtitle, value, name, disabled, error, className = 'checkbox--form', onChange, ...rest }, ref) => (
|
||||
<>
|
||||
<label className={clsx('checkbox', className)}>
|
||||
<span className="checkbox__marker" />
|
||||
@@ -27,6 +27,7 @@ export const Checkbox = forwardRef<HTMLInputElement, Props>(
|
||||
checked={value}
|
||||
onChange={(e) => onChange(e.target.checked)}
|
||||
ref={ref}
|
||||
{...rest}
|
||||
/>
|
||||
<span className="checkbox__label">
|
||||
<span className="checkbox__label-text checkbox__label-text--long">
|
||||
|
||||
@@ -1,29 +1,42 @@
|
||||
import React, { ComponentProps, forwardRef } from 'react';
|
||||
import clsx from 'clsx';
|
||||
import { trimLinesAndRemoveEmpty } from '../../../helpers/helpers';
|
||||
|
||||
type Props = ComponentProps<'textarea'> & {
|
||||
className?: string;
|
||||
label?: string;
|
||||
error?: string;
|
||||
trimOnBlur?: boolean;
|
||||
};
|
||||
|
||||
export const Textarea = forwardRef<HTMLTextAreaElement, Props>(({ name, label, className, error, ...rest }, ref) => (
|
||||
<div className={clsx('form-group', { 'has-error': !!error })}>
|
||||
{label && (
|
||||
<label className="form__label" htmlFor={name}>
|
||||
{label}
|
||||
</label>
|
||||
)}
|
||||
<textarea
|
||||
className={clsx(
|
||||
'form-control form-control--textarea form-control--textarea-small font-monospace',
|
||||
className,
|
||||
export const Textarea = forwardRef<HTMLTextAreaElement, Props>(
|
||||
({ name, label, className, error, trimOnBlur, onBlur, ...rest }, ref) => (
|
||||
<div className={clsx('form-group', { 'has-error': !!error })}>
|
||||
{label && (
|
||||
<label className="form__label" htmlFor={name}>
|
||||
{label}
|
||||
</label>
|
||||
)}
|
||||
ref={ref}
|
||||
{...rest}
|
||||
/>
|
||||
{error && <div className="form__message form__message--error">{error}</div>}
|
||||
</div>
|
||||
));
|
||||
<textarea
|
||||
className={clsx(
|
||||
'form-control form-control--textarea form-control--textarea-small font-monospace',
|
||||
className,
|
||||
)}
|
||||
ref={ref}
|
||||
onBlur={(e) => {
|
||||
if (trimOnBlur) {
|
||||
const normalizedValue = trimLinesAndRemoveEmpty(e.target.value);
|
||||
rest.onChange(normalizedValue);
|
||||
}
|
||||
if (onBlur) {
|
||||
onBlur(e);
|
||||
}
|
||||
}}
|
||||
{...rest}
|
||||
/>
|
||||
{error && <div className="form__message form__message--error">{error}</div>}
|
||||
</div>
|
||||
),
|
||||
);
|
||||
|
||||
Textarea.displayName = 'Textarea';
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
validateIsSafePort,
|
||||
} from '../../../helpers/validators';
|
||||
import { Input } from '../Controls/Input';
|
||||
import { Select } from '../Controls/Select';
|
||||
|
||||
const getDownloadLink = (host: string, clientId: string, protocol: string, invalid: boolean) => {
|
||||
if (!host || invalid) {
|
||||
@@ -62,7 +63,6 @@ export const MobileConfigForm = ({ initialValues }: Props) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const {
|
||||
register,
|
||||
watch,
|
||||
control,
|
||||
formState: { isValid },
|
||||
@@ -101,6 +101,7 @@ export const MobileConfigForm = ({ initialValues }: Props) => {
|
||||
<Input
|
||||
{...field}
|
||||
type="text"
|
||||
data-testid="mobile_config_host"
|
||||
label={t('dhcp_table_hostname')}
|
||||
placeholder={t('form_enter_hostname')}
|
||||
error={fieldState.error?.message}
|
||||
@@ -123,6 +124,7 @@ export const MobileConfigForm = ({ initialValues }: Props) => {
|
||||
<Input
|
||||
{...field}
|
||||
type="number"
|
||||
data-testid="mobile_config_port"
|
||||
label={t('encryption_https')}
|
||||
placeholder={t('encryption_https')}
|
||||
error={fieldState.error?.message}
|
||||
@@ -160,6 +162,7 @@ export const MobileConfigForm = ({ initialValues }: Props) => {
|
||||
<Input
|
||||
{...field}
|
||||
type="text"
|
||||
data-testid="mobile_config_client_id"
|
||||
placeholder={t('client_id_placeholder')}
|
||||
error={fieldState.error?.message}
|
||||
/>
|
||||
@@ -168,14 +171,16 @@ export const MobileConfigForm = ({ initialValues }: Props) => {
|
||||
</div>
|
||||
|
||||
<div className="form__group form__group--settings">
|
||||
<label htmlFor="protocol" className="form__label">
|
||||
{i18next.t('protocol')}
|
||||
</label>
|
||||
|
||||
<select id="protocol" className="form-control" {...register('protocol')}>
|
||||
<option value={MOBILE_CONFIG_LINKS.DOT}>{i18next.t('dns_over_tls')}</option>
|
||||
<option value={MOBILE_CONFIG_LINKS.DOH}>{i18next.t('dns_over_https')}</option>
|
||||
</select>
|
||||
<Controller
|
||||
name="protocol"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Select {...field} label={t('protocol')} data-testid="mobile_config_protocol">
|
||||
<option value={MOBILE_CONFIG_LINKS.DOT}>{i18next.t('dns_over_tls')}</option>
|
||||
<option value={MOBILE_CONFIG_LINKS.DOH}>{i18next.t('dns_over_https')}</option>
|
||||
</Select>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user