Better form validation for required parameters plus live editing
Summary: Taking on the feedback from the demo yesterday, I've improved the required parameter's dialog by showing where specific errors occur in the form and adding live editing to the URI displayed. Reviewed By: danielbuechele Differential Revision: D16802921 fbshipit-source-id: 2e729549306a8efb79ca76d3da6f70632ccd9212
This commit is contained in:
committed by
Facebook Github Bot
parent
1ae3b90019
commit
c40a88b117
@@ -7,7 +7,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {Button, FlexColumn, Input, Sheet, styled, Glyph, colors} from 'flipper';
|
import {Button, FlexColumn, Input, Sheet, styled, Glyph, colors} from 'flipper';
|
||||||
import {replaceRequiredParametersWithValues} from '../util/uri';
|
import {
|
||||||
|
replaceRequiredParametersWithValues,
|
||||||
|
parameterIsNumberType,
|
||||||
|
validateParameter,
|
||||||
|
liveEdit,
|
||||||
|
} from '../util/uri';
|
||||||
import {useRequiredParameterFormValidator} from '../hooks/requiredParameters';
|
import {useRequiredParameterFormValidator} from '../hooks/requiredParameters';
|
||||||
|
|
||||||
import type {URI} from '../flow-types';
|
import type {URI} from '../flow-types';
|
||||||
@@ -36,10 +41,16 @@ const Text = styled('span')({
|
|||||||
lineHeight: 1.3,
|
lineHeight: 1.3,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const ErrorLabel = styled('span')({
|
||||||
|
color: colors.yellow,
|
||||||
|
lineHeight: 1.4,
|
||||||
|
});
|
||||||
|
|
||||||
const URIContainer = styled('div')({
|
const URIContainer = styled('div')({
|
||||||
lineHeight: 1.3,
|
lineHeight: 1.3,
|
||||||
marginLeft: 2,
|
marginLeft: 2,
|
||||||
marginBottom: 8,
|
marginBottom: 8,
|
||||||
|
marginTop: 10,
|
||||||
overflowWrap: 'break-word',
|
overflowWrap: 'break-word',
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -49,8 +60,9 @@ const ButtonContainer = styled('div')({
|
|||||||
|
|
||||||
const RequiredParameterInput = styled(Input)({
|
const RequiredParameterInput = styled(Input)({
|
||||||
margin: 0,
|
margin: 0,
|
||||||
marginBottom: 10,
|
marginTop: 8,
|
||||||
height: 30,
|
height: 30,
|
||||||
|
width: '100%',
|
||||||
});
|
});
|
||||||
|
|
||||||
const WarningIconContainer = styled('span')({
|
const WarningIconContainer = styled('span')({
|
||||||
@@ -81,13 +93,11 @@ export default (props: Props) => {
|
|||||||
</WarningIconContainer>
|
</WarningIconContainer>
|
||||||
<Text>
|
<Text>
|
||||||
This uri has required parameters denoted by {'{parameter}'}.
|
This uri has required parameters denoted by {'{parameter}'}.
|
||||||
Numeric fields are spcified with a '#' symbol. Please fix the
|
|
||||||
errors to navigate to the specified uri.
|
|
||||||
</Text>
|
</Text>
|
||||||
</Title>
|
</Title>
|
||||||
{requiredParameters.map((paramater, idx) => (
|
{requiredParameters.map((paramater, idx) => (
|
||||||
|
<div key={idx}>
|
||||||
<RequiredParameterInput
|
<RequiredParameterInput
|
||||||
key={idx}
|
|
||||||
onChange={event =>
|
onChange={event =>
|
||||||
setValuesArray([
|
setValuesArray([
|
||||||
...values.slice(0, idx),
|
...values.slice(0, idx),
|
||||||
@@ -95,10 +105,17 @@ export default (props: Props) => {
|
|||||||
...values.slice(idx + 1),
|
...values.slice(idx + 1),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
name={paramater}
|
||||||
placeholder={paramater}
|
placeholder={paramater}
|
||||||
/>
|
/>
|
||||||
|
{values[idx] &&
|
||||||
|
parameterIsNumberType(paramater) &&
|
||||||
|
!validateParameter(values[idx], paramater) ? (
|
||||||
|
<ErrorLabel>Parameter must be a number</ErrorLabel>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
))}
|
))}
|
||||||
<URIContainer>{uri}</URIContainer>
|
<URIContainer>{liveEdit(uri, values)}</URIContainer>
|
||||||
<ButtonContainer>
|
<ButtonContainer>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|||||||
@@ -7,14 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {useEffect, useState} from 'react';
|
import {useEffect, useState} from 'react';
|
||||||
import {parameterIsNumberType} from '../util/uri';
|
import {validateParameter} from '../util/uri';
|
||||||
|
|
||||||
const validateParameter = (value: string, parameter: string) => {
|
|
||||||
return (
|
|
||||||
value.length > 0 &&
|
|
||||||
(parameterIsNumberType(parameter) ? !isNaN(parseInt(value, 10)) : true)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const useRequiredParameterFormValidator = (
|
export const useRequiredParameterFormValidator = (
|
||||||
requiredParameters: Array<string>,
|
requiredParameters: Array<string>,
|
||||||
|
|||||||
@@ -112,11 +112,12 @@ export default class extends FlipperPlugin<State, {}, PersistedState> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
navigateTo = (query: string) => {
|
navigateTo = (query: string) => {
|
||||||
this.props.setPersistedState({currentURI: query});
|
const filteredQuery = filterOptionalParameters(query);
|
||||||
const requiredParameters = getRequiredParameters(query);
|
this.props.setPersistedState({currentURI: filteredQuery});
|
||||||
|
const requiredParameters = getRequiredParameters(filteredQuery);
|
||||||
if (requiredParameters.length === 0) {
|
if (requiredParameters.length === 0) {
|
||||||
this.getDevice().then(device => {
|
this.getDevice().then(device => {
|
||||||
device.navigateToLocation(filterOptionalParameters(query));
|
device.navigateToLocation(filterOptionalParameters(filteredQuery));
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.setState({
|
this.setState({
|
||||||
|
|||||||
@@ -8,6 +8,13 @@
|
|||||||
|
|
||||||
import querystring from 'querystring';
|
import querystring from 'querystring';
|
||||||
|
|
||||||
|
export const validateParameter = (value: string, parameter: string) => {
|
||||||
|
return (
|
||||||
|
value &&
|
||||||
|
(parameterIsNumberType(parameter) ? !isNaN(parseInt(value, 10)) : true)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export const filterOptionalParameters: string => string = (uri: string) => {
|
export const filterOptionalParameters: string => string = (uri: string) => {
|
||||||
return uri.replace(/[/&]?([^&?={}\/]*=)?{\?.*?}/g, '');
|
return uri.replace(/[/&]?([^&?={}\/]*=)?{\?.*?}/g, '');
|
||||||
};
|
};
|
||||||
@@ -62,3 +69,15 @@ export const getRequiredParameters = (uri: string) => {
|
|||||||
}
|
}
|
||||||
return matches;
|
return matches;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const liveEdit = (uri: string, formValues: Array<string>): string => {
|
||||||
|
const parameterRegExp = /({[^?]*?})/g;
|
||||||
|
const uriArray = uri.split(parameterRegExp);
|
||||||
|
return uriArray.reduce((acc, uriComponent, idx) => {
|
||||||
|
if (idx % 2 === 0 || !formValues[(idx - 1) / 2]) {
|
||||||
|
return acc + uriComponent;
|
||||||
|
} else {
|
||||||
|
return acc + formValues[(idx - 1) / 2];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user