mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Copied from new timepicker and unified component branch
This commit is contained in:
@@ -1,53 +0,0 @@
|
||||
import React from 'react';
|
||||
import renderer from 'react-test-renderer';
|
||||
import { shallow } from 'enzyme';
|
||||
import { Input, EventsWithValidation } from './Input';
|
||||
import { ValidationEvents } from 'app/types';
|
||||
|
||||
const TEST_ERROR_MESSAGE = 'Value must be empty or less than 3 chars';
|
||||
const testBlurValidation: ValidationEvents = {
|
||||
[EventsWithValidation.onBlur]: [
|
||||
{
|
||||
rule: (value: string) => {
|
||||
if (!value || value.length < 3) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
errorMessage: TEST_ERROR_MESSAGE,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
describe('Input', () => {
|
||||
it('renders correctly', () => {
|
||||
const tree = renderer.create(<Input />).toJSON();
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should validate with error onBlur', () => {
|
||||
const wrapper = shallow(<Input validationEvents={testBlurValidation} />);
|
||||
const evt = {
|
||||
persist: jest.fn,
|
||||
target: {
|
||||
value: 'I can not be more than 2 chars',
|
||||
},
|
||||
};
|
||||
|
||||
wrapper.find('input').simulate('blur', evt);
|
||||
expect(wrapper.state('error')).toBe(TEST_ERROR_MESSAGE);
|
||||
});
|
||||
|
||||
it('should validate without error onBlur', () => {
|
||||
const wrapper = shallow(<Input validationEvents={testBlurValidation} />);
|
||||
const evt = {
|
||||
persist: jest.fn,
|
||||
target: {
|
||||
value: 'Hi',
|
||||
},
|
||||
};
|
||||
|
||||
wrapper.find('input').simulate('blur', evt);
|
||||
expect(wrapper.state('error')).toBe(null);
|
||||
});
|
||||
});
|
||||
@@ -1,94 +0,0 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { ValidationEvents, ValidationRule } from 'app/types';
|
||||
import { validate, hasValidationEvent } from 'app/core/utils/validate';
|
||||
|
||||
export enum InputStatus {
|
||||
Invalid = 'invalid',
|
||||
Valid = 'valid',
|
||||
}
|
||||
|
||||
export enum InputTypes {
|
||||
Text = 'text',
|
||||
Number = 'number',
|
||||
Password = 'password',
|
||||
Email = 'email',
|
||||
}
|
||||
|
||||
export enum EventsWithValidation {
|
||||
onBlur = 'onBlur',
|
||||
onFocus = 'onFocus',
|
||||
onChange = 'onChange',
|
||||
}
|
||||
|
||||
interface Props extends React.HTMLProps<HTMLInputElement> {
|
||||
validationEvents?: ValidationEvents;
|
||||
hideErrorMessage?: boolean;
|
||||
|
||||
// Override event props and append status as argument
|
||||
onBlur?: (event: React.FocusEvent<HTMLInputElement>, status?: InputStatus) => void;
|
||||
onFocus?: (event: React.FocusEvent<HTMLInputElement>, status?: InputStatus) => void;
|
||||
onChange?: (event: React.FormEvent<HTMLInputElement>, status?: InputStatus) => void;
|
||||
}
|
||||
|
||||
export class Input extends PureComponent<Props> {
|
||||
static defaultProps = {
|
||||
className: '',
|
||||
};
|
||||
|
||||
state = {
|
||||
error: null,
|
||||
};
|
||||
|
||||
get status() {
|
||||
return this.state.error ? InputStatus.Invalid : InputStatus.Valid;
|
||||
}
|
||||
|
||||
get isInvalid() {
|
||||
return this.status === InputStatus.Invalid;
|
||||
}
|
||||
|
||||
validatorAsync = (validationRules: ValidationRule[]) => {
|
||||
return evt => {
|
||||
const errors = validate(evt.target.value, validationRules);
|
||||
this.setState(prevState => {
|
||||
return {
|
||||
...prevState,
|
||||
error: errors ? errors[0] : null,
|
||||
};
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
populateEventPropsWithStatus = (restProps, validationEvents: ValidationEvents) => {
|
||||
const inputElementProps = { ...restProps };
|
||||
Object.keys(EventsWithValidation).forEach((eventName: EventsWithValidation) => {
|
||||
if (hasValidationEvent(eventName, validationEvents) || restProps[eventName]) {
|
||||
inputElementProps[eventName] = async evt => {
|
||||
evt.persist(); // Needed for async. https://reactjs.org/docs/events.html#event-pooling
|
||||
if (hasValidationEvent(eventName, validationEvents)) {
|
||||
await this.validatorAsync(validationEvents[eventName]).apply(this, [evt]);
|
||||
}
|
||||
if (restProps[eventName]) {
|
||||
restProps[eventName].apply(null, [evt, this.status]);
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
return inputElementProps;
|
||||
};
|
||||
|
||||
render() {
|
||||
const { validationEvents, className, hideErrorMessage, ...restProps } = this.props;
|
||||
const { error } = this.state;
|
||||
const inputClassName = classNames('gf-form-input', { invalid: this.isInvalid }, className);
|
||||
const inputElementProps = this.populateEventPropsWithStatus(restProps, validationEvents);
|
||||
|
||||
return (
|
||||
<div className="our-custom-wrapper-class">
|
||||
<input {...inputElementProps} className={inputClassName} />
|
||||
{error && !hideErrorMessage && <span>{error}</span>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Input renders correctly 1`] = `
|
||||
<div
|
||||
className="our-custom-wrapper-class"
|
||||
>
|
||||
<input
|
||||
className="gf-form-input"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
@@ -1 +0,0 @@
|
||||
export { Input } from './Input';
|
||||
@@ -1,16 +0,0 @@
|
||||
import { ValidationRule, ValidationEvents } from 'app/types';
|
||||
import { EventsWithValidation } from 'app/core/components/Form/Input';
|
||||
|
||||
export const validate = (value: string, validationRules: ValidationRule[]) => {
|
||||
const errors = validationRules.reduce((acc, currRule) => {
|
||||
if (!currRule.rule(value)) {
|
||||
return acc.concat(currRule.errorMessage);
|
||||
}
|
||||
return acc;
|
||||
}, []);
|
||||
return errors.length > 0 ? errors : null;
|
||||
};
|
||||
|
||||
export const hasValidationEvent = (event: EventsWithValidation, validationEvents: ValidationEvents) => {
|
||||
return validationEvents && validationEvents[event];
|
||||
};
|
||||
Reference in New Issue
Block a user