Merge branch 'releases/v4' of github.com:strapi/strapi into v4/ctb

This commit is contained in:
soupette 2021-10-07 09:48:09 +02:00
commit e2fdcee602
8 changed files with 474 additions and 585 deletions

View File

@ -1,347 +0,0 @@
/**
*
* GenericInput
* This is a temp file move it to the helper plugin when ready
*/
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import { useIntl } from 'react-intl';
import cloneDeep from 'lodash/cloneDeep';
import { formatISO } from 'date-fns';
import { DatePicker } from '@strapi/parts/DatePicker';
import { NumberInput } from '@strapi/parts/NumberInput';
import { Select, Option } from '@strapi/parts/Select';
import { Textarea } from '@strapi/parts/Textarea';
import { TextInput } from '@strapi/parts/TextInput';
import { TimePicker } from '@strapi/parts/TimePicker';
import { ToggleInput } from '@strapi/parts/ToggleInput';
import Hide from '@strapi/icons/Hide';
import Show from '@strapi/icons/Show';
const GenericInput = ({
autoComplete,
customInputs,
description,
disabled,
intlLabel,
labelAction,
error,
name,
onChange,
options,
placeholder,
step,
type,
value,
...rest
}) => {
const { formatMessage } = useIntl();
const [showPassword, setShowPassword] = useState(false);
const CustomInput = customInputs ? customInputs[type] : null;
if (CustomInput) {
return (
<CustomInput
{...rest}
description={description}
disabled={disabled}
intlLabel={intlLabel}
labelAction={labelAction}
error={error}
name={name}
onChange={onChange}
placeholder={placeholder}
type={type}
value={value}
/>
);
}
const label = intlLabel.id
? formatMessage(
{ id: intlLabel.id, defaultMessage: intlLabel.defaultMessage },
{ ...intlLabel.values }
)
: name;
const hint = description
? formatMessage(
{ id: description.id, defaultMessage: description.defaultMessage },
{ ...description.values }
)
: '';
const formattedPlaceholder = placeholder
? formatMessage(
{ id: placeholder.id, defaultMessage: placeholder.defaultMessage },
{ ...placeholder.values }
)
: '';
const errorMessage = error ? formatMessage({ id: error, defaultMessage: error }) : '';
switch (type) {
case 'bool': {
return (
<ToggleInput
checked={value || false}
disabled={disabled}
hint={hint}
label={label}
labelAction={labelAction}
name={name}
offLabel={formatMessage({
id: 'app.components.ToggleCheckbox.off-label',
defaultMessage: 'Off',
})}
onLabel={formatMessage({
id: 'app.components.ToggleCheckbox.on-label',
defaultMessage: 'On',
})}
onChange={e => {
onChange({ target: { name, value: e.target.checked } });
}}
/>
);
}
case 'date': {
return (
<DatePicker
clearLabel={formatMessage({ id: 'clearLabel', defaultMessage: 'Clear' })}
disabled={disabled}
error={errorMessage}
label={label}
labelAction={labelAction}
id={name}
hint={hint}
name={name}
onChange={date => {
const formattedDate = formatISO(cloneDeep(date), { representation: 'date' });
onChange({ target: { name, value: formattedDate, type } });
}}
onClear={() => onChange({ target: { name, value: '', type } })}
placeholder={formattedPlaceholder}
selectedDate={value ? new Date(value) : null}
selectedDateLabel={formattedDate => `Date picker, current is ${formattedDate}`}
/>
);
}
case 'number': {
return (
<NumberInput
disabled={disabled}
error={errorMessage}
label={label}
labelAction={labelAction}
id={name}
hint={hint}
name={name}
onValueChange={value => {
onChange({ target: { name, value, type } });
}}
placeholder={formattedPlaceholder}
step={step}
value={value || undefined}
/>
);
}
case 'email':
case 'text':
case 'string': {
return (
<TextInput
autoComplete={autoComplete}
disabled={disabled}
error={errorMessage}
label={label}
labelAction={labelAction}
id={name}
hint={hint}
name={name}
onChange={onChange}
placeholder={formattedPlaceholder}
type={type}
value={value || ''}
/>
);
}
case 'password': {
return (
<TextInput
autoComplete={autoComplete}
disabled={disabled}
error={errorMessage}
endAction={
<button
aria-label={formatMessage({
id: 'Auth.form.password.show-password',
defaultMessage: 'Show password',
})}
onClick={() => {
setShowPassword(prev => !prev);
}}
style={{
border: 'none',
padding: 0,
background: 'transparent',
}}
type="button"
>
{showPassword ? <Show /> : <Hide />}
</button>
}
label={label}
labelAction={labelAction}
id={name}
hint={hint}
name={name}
onChange={onChange}
placeholder={formattedPlaceholder}
type={showPassword ? 'text' : 'password'}
value={value || ''}
/>
);
}
case 'select': {
return (
<Select
disabled={disabled}
error={errorMessage}
label={label}
labelAction={labelAction}
id={name}
hint={hint}
name={name}
onChange={value => {
onChange({ target: { name, value: value === '' ? null : value, type: 'select' } });
}}
placeholder={formattedPlaceholder}
value={value || ''}
>
{options.map(({ metadatas: { intlLabel, disabled, hidden }, key, value }) => {
return (
<Option key={key} value={value} disabled={disabled} hidden={hidden}>
{formatMessage(intlLabel)}
</Option>
);
})}
</Select>
);
}
case 'textarea': {
return (
<Textarea
disabled={disabled}
error={errorMessage}
label={label}
labelAction={labelAction}
id={name}
hint={hint}
name={name}
onChange={onChange}
placeholder={formattedPlaceholder}
type={type}
value={value || ''}
>
{value}
</Textarea>
);
}
case 'time': {
let time = value;
// The backend send a value which has the following format: '00:45:00.000'
// or the time picker only supports hours & minutes so we need to mutate the value
if (value && value.split(':').length > 2) {
time = time.split(':');
time.pop();
time = time.join(':');
}
return (
<TimePicker
clearLabel={formatMessage({ id: 'clearLabel', defaultMessage: 'Clear' })}
disabled={disabled}
error={errorMessage}
label={label}
labelAction={labelAction}
id={name}
hint={hint}
name={name}
onChange={time => {
onChange({ target: { name, value: `${time}`, type } });
}}
onClear={() => {
onChange({ target: { name, value: null, type } });
}}
placeholder={formattedPlaceholder}
step={step}
value={time}
/>
);
}
default: {
return <div>{type} is not supported</div>;
}
}
};
GenericInput.defaultProps = {
autoComplete: undefined,
customInputs: null,
description: null,
disabled: false,
error: '',
labelAction: undefined,
placeholder: null,
options: [],
step: 1,
value: '',
};
GenericInput.propTypes = {
autoComplete: PropTypes.string,
customInputs: PropTypes.object,
description: PropTypes.shape({
id: PropTypes.string.isRequired,
defaultMessage: PropTypes.string.isRequired,
values: PropTypes.object,
}),
disabled: PropTypes.bool,
error: PropTypes.string,
intlLabel: PropTypes.shape({
id: PropTypes.string.isRequired,
defaultMessage: PropTypes.string.isRequired,
values: PropTypes.object,
}).isRequired,
labelAction: PropTypes.element,
name: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired,
options: PropTypes.arrayOf(
PropTypes.shape({
metadatas: PropTypes.shape({
intlLabel: PropTypes.shape({
id: PropTypes.string.isRequired,
defaultMessage: PropTypes.string.isRequired,
}).isRequired,
disabled: PropTypes.bool,
hidden: PropTypes.bool,
}).isRequired,
key: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
}).isRequired
),
placeholder: PropTypes.shape({
id: PropTypes.string.isRequired,
defaultMessage: PropTypes.string.isRequired,
values: PropTypes.object,
}),
step: PropTypes.number,
type: PropTypes.string.isRequired,
value: PropTypes.any,
};
export default GenericInput;

View File

@ -5,6 +5,7 @@ import omit from 'lodash/omit';
import take from 'lodash/take';
import isEqual from 'react-fast-compare';
import {
GenericInput,
NotAllowedInput,
// useLibrary
} from '@strapi/helper-plugin';
@ -13,7 +14,6 @@ import { getFieldName } from '../../utils';
import Wysiwyg from '../Wysiwyg';
import InputJSON from '../InputJSON';
import ComingSoonInput from './ComingSoonInput';
import GenericInput from './GenericInput';
import InputUID from '../InputUID';
import SelectWrapper from '../SelectWrapper';

View File

@ -792,7 +792,7 @@ describe('ADMIN | Pages | Profile page', () => {
>
<label
class="c24"
for="textinput-1"
for="firstname"
>
First name
</label>
@ -804,7 +804,7 @@ describe('ADMIN | Pages | Profile page', () => {
aria-disabled="false"
aria-invalid="false"
class="c27"
id="textinput-1"
id="firstname"
name="firstname"
placeholder=""
type="text"
@ -832,7 +832,7 @@ describe('ADMIN | Pages | Profile page', () => {
>
<label
class="c24"
for="textinput-2"
for="lastname"
>
Last name
</label>
@ -844,7 +844,7 @@ describe('ADMIN | Pages | Profile page', () => {
aria-disabled="false"
aria-invalid="false"
class="c27"
id="textinput-2"
id="lastname"
name="lastname"
placeholder=""
type="text"
@ -872,7 +872,7 @@ describe('ADMIN | Pages | Profile page', () => {
>
<label
class="c24"
for="textinput-3"
for="email"
>
Email
</label>
@ -884,7 +884,7 @@ describe('ADMIN | Pages | Profile page', () => {
aria-disabled="false"
aria-invalid="false"
class="c27"
id="textinput-3"
id="email"
name="email"
placeholder=""
type="email"
@ -912,7 +912,7 @@ describe('ADMIN | Pages | Profile page', () => {
>
<label
class="c24"
for="textinput-4"
for="username"
>
Username
</label>
@ -924,7 +924,7 @@ describe('ADMIN | Pages | Profile page', () => {
aria-disabled="false"
aria-invalid="false"
class="c27"
id="textinput-4"
id="username"
name="username"
placeholder=""
type="text"
@ -969,7 +969,7 @@ describe('ADMIN | Pages | Profile page', () => {
>
<label
class="c24"
for="textinput-5"
for="textinput-1"
>
Password
</label>
@ -981,7 +981,7 @@ describe('ADMIN | Pages | Profile page', () => {
aria-disabled="false"
aria-invalid="false"
class="c28"
id="textinput-5"
id="textinput-1"
name="password"
type="password"
value=""
@ -1030,7 +1030,7 @@ describe('ADMIN | Pages | Profile page', () => {
>
<label
class="c24"
for="textinput-6"
for="textinput-2"
>
Password confirmation
</label>
@ -1042,7 +1042,7 @@ describe('ADMIN | Pages | Profile page', () => {
aria-disabled="false"
aria-invalid="false"
class="c28"
id="textinput-6"
id="textinput-2"
name="confirmPassword"
type="password"
value=""

View File

@ -486,88 +486,6 @@ exports[`<EditPage /> renders and matches the snapshot 1`] = `
margin-top: 4px;
}
.c37 {
height: 100vh;
}
.c1 {
background: #f6f6f9;
padding-top: 56px;
padding-right: 56px;
padding-bottom: 56px;
padding-left: 56px;
}
.c13 {
padding-right: 56px;
padding-left: 56px;
}
.c2 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
-webkit-box-pack: justify;
-webkit-justify-content: space-between;
-ms-flex-pack: justify;
justify-content: space-between;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.c3 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.c4 {
font-weight: 600;
font-size: 2rem;
line-height: 1.25;
color: #32324d;
}
.c11 {
font-weight: 400;
font-size: 0.875rem;
line-height: 1.43;
color: #666687;
}
.c12 {
font-size: 1rem;
line-height: 1.5;
}
.c0 {
outline: none;
}
.c22 {
display: grid;
grid-template-columns: repeat(12,1fr);
gap: 16px;
}
.c23 {
grid-column: span 6;
}
.c33 {
font-weight: 500;
font-size: 0.75rem;
@ -700,6 +618,88 @@ exports[`<EditPage /> renders and matches the snapshot 1`] = `
opacity: 1;
}
.c37 {
height: 100vh;
}
.c1 {
background: #f6f6f9;
padding-top: 56px;
padding-right: 56px;
padding-bottom: 56px;
padding-left: 56px;
}
.c13 {
padding-right: 56px;
padding-left: 56px;
}
.c2 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
-webkit-box-pack: justify;
-webkit-justify-content: space-between;
-ms-flex-pack: justify;
justify-content: space-between;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.c3 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.c4 {
font-weight: 600;
font-size: 2rem;
line-height: 1.25;
color: #32324d;
}
.c11 {
font-weight: 400;
font-size: 0.875rem;
line-height: 1.43;
color: #666687;
}
.c12 {
font-size: 1rem;
line-height: 1.5;
}
.c0 {
outline: none;
}
.c22 {
display: grid;
grid-template-columns: repeat(12,1fr);
gap: 16px;
}
.c23 {
grid-column: span 6;
}
@media (max-width:68.75rem) {
.c23 {
grid-column: span;

View File

@ -1,4 +1,5 @@
import React from 'react';
import styled from 'styled-components';
import { RemoveRoundedButton } from '@strapi/helper-plugin';
import AddIcon from '@strapi/icons/AddIcon';
import { Box } from '@strapi/parts/Box';
@ -11,6 +12,10 @@ import { TextButton } from '@strapi/parts/TextButton';
import { Field, FieldArray, useFormikContext } from 'formik';
import { useIntl } from 'react-intl';
const RemoveButtonContainer = styled(Row)`
height: ${({ theme }) => theme.sizes.input.M};
`;
const HeadersInput = () => {
const { formatMessage } = useIntl();
const { values, errors } = useFormikContext();
@ -51,7 +56,7 @@ const HeadersInput = () => {
/>
</GridItem>
<GridItem col={6}>
<Row>
<Row alignItems="flex-end">
<Box style={{ flex: 1 }}>
<Field
as={TextInput}
@ -70,7 +75,7 @@ const HeadersInput = () => {
}
/>
</Box>
<Box paddingLeft={2}>
<RemoveButtonContainer paddingLeft={2}>
<RemoveRoundedButton
onClick={() => values.headers.length !== 1 && remove(i)}
label={formatMessage(
@ -81,7 +86,7 @@ const HeadersInput = () => {
{ number: i + 1 }
)}
/>
</Box>
</RemoveButtonContainer>
</Row>
</GridItem>
</React.Fragment>

View File

@ -479,88 +479,6 @@ exports[`<CreatePage /> renders and matches the snapshot 1`] = `
margin-top: 4px;
}
.c37 {
height: 100vh;
}
.c1 {
background: #f6f6f9;
padding-top: 56px;
padding-right: 56px;
padding-bottom: 56px;
padding-left: 56px;
}
.c14 {
padding-right: 56px;
padding-left: 56px;
}
.c2 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
-webkit-box-pack: justify;
-webkit-justify-content: space-between;
-ms-flex-pack: justify;
justify-content: space-between;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.c3 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.c4 {
font-weight: 600;
font-size: 2rem;
line-height: 1.25;
color: #32324d;
}
.c12 {
font-weight: 400;
font-size: 0.875rem;
line-height: 1.43;
color: #666687;
}
.c13 {
font-size: 1rem;
line-height: 1.5;
}
.c22 {
display: grid;
grid-template-columns: repeat(12,1fr);
gap: 16px;
}
.c23 {
grid-column: span 6;
}
.c0 {
outline: none;
}
.c33 {
font-weight: 500;
font-size: 0.75rem;
@ -693,6 +611,88 @@ exports[`<CreatePage /> renders and matches the snapshot 1`] = `
opacity: 1;
}
.c37 {
height: 100vh;
}
.c1 {
background: #f6f6f9;
padding-top: 56px;
padding-right: 56px;
padding-bottom: 56px;
padding-left: 56px;
}
.c14 {
padding-right: 56px;
padding-left: 56px;
}
.c2 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
-webkit-box-pack: justify;
-webkit-justify-content: space-between;
-ms-flex-pack: justify;
justify-content: space-between;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.c3 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.c4 {
font-weight: 600;
font-size: 2rem;
line-height: 1.25;
color: #32324d;
}
.c12 {
font-weight: 400;
font-size: 0.875rem;
line-height: 1.43;
color: #666687;
}
.c13 {
font-size: 1rem;
line-height: 1.5;
}
.c22 {
display: grid;
grid-template-columns: repeat(12,1fr);
gap: 16px;
}
.c23 {
grid-column: span 6;
}
.c0 {
outline: none;
}
.c21 {
border: 1px solid #d9d8ff;
background: #f0f0ff;

View File

@ -1,32 +1,71 @@
/**
*
* Input
* GenericInput
*
*/
import React from 'react';
import { useIntl } from 'react-intl';
import { ToggleInput } from '@strapi/parts/ToggleInput';
import { TextInput } from '@strapi/parts/TextInput';
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import { useIntl } from 'react-intl';
import cloneDeep from 'lodash/cloneDeep';
import { formatISO } from 'date-fns';
import { DatePicker } from '@strapi/parts/DatePicker';
import { NumberInput } from '@strapi/parts/NumberInput';
import { Select, Option } from '@strapi/parts/Select';
import { Textarea } from '@strapi/parts/Textarea';
import { TextInput } from '@strapi/parts/TextInput';
import { TimePicker } from '@strapi/parts/TimePicker';
import { ToggleInput } from '@strapi/parts/ToggleInput';
import Hide from '@strapi/icons/Hide';
import Show from '@strapi/icons/Show';
const Input = ({
const GenericInput = ({
autoComplete,
customInputs,
description,
disabled,
intlLabel,
labelAction,
error,
name,
onChange,
options,
placeholder,
step,
type,
value,
...rest
}) => {
const { formatMessage } = useIntl();
const [showPassword, setShowPassword] = useState(false);
const label = formatMessage(
const CustomInput = customInputs ? customInputs[type] : null;
if (CustomInput) {
return (
<CustomInput
{...rest}
description={description}
disabled={disabled}
intlLabel={intlLabel}
labelAction={labelAction}
error={error}
name={name}
onChange={onChange}
placeholder={placeholder}
type={type}
value={value}
/>
);
}
const label = intlLabel.id
? formatMessage(
{ id: intlLabel.id, defaultMessage: intlLabel.defaultMessage },
{ ...intlLabel.values }
);
)
: name;
const hint = description
? formatMessage(
{ id: description.id, defaultMessage: description.defaultMessage },
@ -34,13 +73,24 @@ const Input = ({
)
: '';
if (type === 'bool') {
const formattedPlaceholder = placeholder
? formatMessage(
{ id: placeholder.id, defaultMessage: placeholder.defaultMessage },
{ ...placeholder.values }
)
: '';
const errorMessage = error ? formatMessage({ id: error, defaultMessage: error }) : '';
switch (type) {
case 'bool': {
return (
<ToggleInput
checked={value}
checked={value || false}
disabled={disabled}
hint={hint}
label={label}
labelAction={labelAction}
name={name}
offLabel={formatMessage({
id: 'app.components.ToggleCheckbox.off-label',
@ -56,40 +106,205 @@ const Input = ({
/>
);
}
const formattedPlaceholder = placeholder
? formatMessage(
{ id: placeholder.id, defaultMessage: placeholder.defaultMessage },
{ ...placeholder.values }
)
: '';
const errorMessage = error ? formatMessage({ id: error, defaultMessage: error }) : '';
case 'date': {
return (
<TextInput
<DatePicker
clearLabel={formatMessage({ id: 'clearLabel', defaultMessage: 'Clear' })}
disabled={disabled}
error={errorMessage}
label={label}
labelAction={labelAction}
id={name}
hint={hint}
name={name}
onChange={date => {
const formattedDate = formatISO(cloneDeep(date), { representation: 'date' });
onChange({ target: { name, value: formattedDate, type } });
}}
onClear={() => onChange({ target: { name, value: '', type } })}
placeholder={formattedPlaceholder}
selectedDate={value ? new Date(value) : null}
selectedDateLabel={formattedDate => `Date picker, current is ${formattedDate}`}
/>
);
}
case 'number': {
return (
<NumberInput
disabled={disabled}
error={errorMessage}
label={label}
labelAction={labelAction}
id={name}
hint={hint}
name={name}
onValueChange={value => {
onChange({ target: { name, value, type } });
}}
placeholder={formattedPlaceholder}
step={step}
value={value || undefined}
/>
);
}
case 'email':
case 'text':
case 'string': {
return (
<TextInput
autoComplete={autoComplete}
disabled={disabled}
error={errorMessage}
label={label}
labelAction={labelAction}
id={name}
hint={hint}
name={name}
onChange={onChange}
placeholder={formattedPlaceholder}
type={type}
value={value}
value={value || ''}
/>
);
}
case 'password': {
return (
<TextInput
autoComplete={autoComplete}
disabled={disabled}
error={errorMessage}
endAction={
<button
aria-label={formatMessage({
id: 'Auth.form.password.show-password',
defaultMessage: 'Show password',
})}
onClick={() => {
setShowPassword(prev => !prev);
}}
style={{
border: 'none',
padding: 0,
background: 'transparent',
}}
type="button"
>
{showPassword ? <Show /> : <Hide />}
</button>
}
label={label}
labelAction={labelAction}
id={name}
hint={hint}
name={name}
onChange={onChange}
placeholder={formattedPlaceholder}
type={showPassword ? 'text' : 'password'}
value={value || ''}
/>
);
}
case 'select': {
return (
<Select
disabled={disabled}
error={errorMessage}
label={label}
labelAction={labelAction}
id={name}
hint={hint}
name={name}
onChange={value => {
onChange({ target: { name, value: value === '' ? null : value, type: 'select' } });
}}
placeholder={formattedPlaceholder}
value={value || ''}
>
{options.map(({ metadatas: { intlLabel, disabled, hidden }, key, value }) => {
return (
<Option key={key} value={value} disabled={disabled} hidden={hidden}>
{formatMessage(intlLabel)}
</Option>
);
})}
</Select>
);
}
case 'textarea': {
return (
<Textarea
disabled={disabled}
error={errorMessage}
label={label}
labelAction={labelAction}
id={name}
hint={hint}
name={name}
onChange={onChange}
placeholder={formattedPlaceholder}
type={type}
value={value || ''}
>
{value}
</Textarea>
);
}
case 'time': {
let time = value;
// The backend send a value which has the following format: '00:45:00.000'
// or the time picker only supports hours & minutes so we need to mutate the value
if (value && value.split(':').length > 2) {
time = time.split(':');
time.pop();
time = time.join(':');
}
return (
<TimePicker
clearLabel={formatMessage({ id: 'clearLabel', defaultMessage: 'Clear' })}
disabled={disabled}
error={errorMessage}
label={label}
labelAction={labelAction}
id={name}
hint={hint}
name={name}
onChange={time => {
onChange({ target: { name, value: `${time}`, type } });
}}
onClear={() => {
onChange({ target: { name, value: null, type } });
}}
placeholder={formattedPlaceholder}
step={step}
value={time}
/>
);
}
default: {
return <div>{type} is not supported</div>;
}
}
};
Input.defaultProps = {
GenericInput.defaultProps = {
autoComplete: undefined,
customInputs: null,
description: null,
disabled: false,
error: '',
labelAction: undefined,
placeholder: null,
options: [],
step: 1,
value: '',
};
Input.propTypes = {
GenericInput.propTypes = {
autoComplete: PropTypes.string,
customInputs: PropTypes.object,
description: PropTypes.shape({
id: PropTypes.string.isRequired,
defaultMessage: PropTypes.string.isRequired,
@ -102,15 +317,31 @@ Input.propTypes = {
defaultMessage: PropTypes.string.isRequired,
values: PropTypes.object,
}).isRequired,
labelAction: PropTypes.element,
name: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired,
options: PropTypes.arrayOf(
PropTypes.shape({
metadatas: PropTypes.shape({
intlLabel: PropTypes.shape({
id: PropTypes.string.isRequired,
defaultMessage: PropTypes.string.isRequired,
}).isRequired,
disabled: PropTypes.bool,
hidden: PropTypes.bool,
}).isRequired,
key: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
}).isRequired
),
placeholder: PropTypes.shape({
id: PropTypes.string.isRequired,
defaultMessage: PropTypes.string.isRequired,
values: PropTypes.object,
}),
step: PropTypes.number,
type: PropTypes.string.isRequired,
value: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]),
value: PropTypes.any,
};
export default Input;
export default GenericInput;

View File

@ -1115,7 +1115,7 @@ describe('ADMIN | Pages | Settings | Advanced Settings', () => {
>
<label
class="c53"
for="textinput-1"
for="email_reset_password"
>
Reset password page
</label>
@ -1124,11 +1124,11 @@ describe('ADMIN | Pages | Settings | Advanced Settings', () => {
class="c54 c55"
>
<input
aria-describedby="textinput-1-hint"
aria-describedby="email_reset_password-hint"
aria-disabled="false"
aria-invalid="false"
class="c56"
id="textinput-1"
id="email_reset_password"
name="email_reset_password"
placeholder="ex: https://youtfrontend.com/reset-password"
type="text"
@ -1137,7 +1137,7 @@ describe('ADMIN | Pages | Settings | Advanced Settings', () => {
</div>
<p
class="c57"
id="textinput-1-hint"
id="email_reset_password-hint"
>
URL of your application's reset password page.
</p>
@ -1232,7 +1232,7 @@ describe('ADMIN | Pages | Settings | Advanced Settings', () => {
>
<label
class="c53"
for="textinput-2"
for="email_confirmation_redirection"
>
Redirection url
</label>
@ -1242,11 +1242,11 @@ describe('ADMIN | Pages | Settings | Advanced Settings', () => {
disabled=""
>
<input
aria-describedby="textinput-2-hint"
aria-describedby="email_confirmation_redirection-hint"
aria-disabled="true"
aria-invalid="false"
class="c56"
id="textinput-2"
id="email_confirmation_redirection"
name="email_confirmation_redirection"
placeholder="ex: https://youtfrontend.com/reset-password"
type="text"
@ -1255,7 +1255,7 @@ describe('ADMIN | Pages | Settings | Advanced Settings', () => {
</div>
<p
class="c57"
id="textinput-2-hint"
id="email_confirmation_redirection-hint"
>
After you confirmed your email, choose where you will be redirected.
</p>