Fix component types of 'components/widgets/settings/text_setting.tsx' (#23919)

Этот коммит содержится в:
M-ZubairAhmed
2023-07-12 16:25:05 +05:30
коммит произвёл GitHub
родитель 98da282f7c
Коммит 5e3c03a0a8
15 изменённых файлов: 136 добавлений и 276 удалений

Просмотреть файл

@@ -76,7 +76,6 @@ exports[`components/BleveSettings should match snapshot, disabled 1`] = `
}
onChange={[Function]}
setByEnv={false}
type="input"
value=""
/>
<div
@@ -336,7 +335,6 @@ exports[`components/BleveSettings should match snapshot, enabled 1`] = `
}
onChange={[Function]}
setByEnv={false}
type="input"
value="bleve.idx"
/>
<div

Просмотреть файл

@@ -126,7 +126,6 @@ exports[`components/PushSettings should match snapshot, licensed 1`] = `
onChange={[Function]}
placeholder="E.g.: \\"https://push-test.mattermost.com\\""
setByEnv={false}
type="input"
value="https://push.mattermost.com"
/>
<AdminTextSetting
@@ -262,7 +261,6 @@ exports[`components/PushSettings should match snapshot, unlicensed 1`] = `
onChange={[Function]}
placeholder="E.g.: \\"https://push-test.mattermost.com\\""
setByEnv={false}
type="input"
value="https://push.mattermost.com"
/>
<AdminTextSetting

Просмотреть файл

@@ -160,7 +160,6 @@ export default class BleveSettings extends AdminSettings<Props, State> {
onChange={this.handleSettingChanged}
setByEnv={this.isSetByEnv('BleveSettings.IndexDir')}
disabled={this.props.isDisabled}
type='input'
/>
<div className='form-group'>
<label

Просмотреть файл

@@ -275,7 +275,6 @@ exports[`components/PluginManagement should match snapshot 1`] = `
}
onChange={[Function]}
setByEnv={false}
type="input"
value="marketplace.example.com"
/>
<div
@@ -624,7 +623,6 @@ exports[`components/PluginManagement should match snapshot when \`Enable Marketp
}
onChange={[Function]}
setByEnv={false}
type="input"
value="marketplace.example.com"
/>
<div
@@ -1069,7 +1067,6 @@ exports[`components/PluginManagement should match snapshot when \`Enable Remote
}
onChange={[Function]}
setByEnv={false}
type="input"
value="marketplace.example.com"
/>
<div
@@ -1420,7 +1417,6 @@ exports[`components/PluginManagement should match snapshot when \`Require Signat
}
onChange={[Function]}
setByEnv={false}
type="input"
value="marketplace.example.com"
/>
<div
@@ -1769,7 +1765,6 @@ exports[`components/PluginManagement should match snapshot, No installed plugins
}
onChange={[Function]}
setByEnv={false}
type="input"
value="marketplace.example.com"
/>
<div
@@ -2122,7 +2117,6 @@ exports[`components/PluginManagement should match snapshot, allow insecure URL e
}
onChange={[Function]}
setByEnv={false}
type="input"
value="marketplace.example.com"
/>
<div
@@ -2473,7 +2467,6 @@ exports[`components/PluginManagement should match snapshot, disabled 1`] = `
}
onChange={[Function]}
setByEnv={false}
type="input"
value="marketplace.example.com"
/>
</SettingsGroup>
@@ -2797,7 +2790,6 @@ exports[`components/PluginManagement should match snapshot, text entered into th
}
onChange={[Function]}
setByEnv={false}
type="input"
value="marketplace.example.com"
/>
<div
@@ -3153,7 +3145,6 @@ exports[`components/PluginManagement should match snapshot, upload disabled 1`]
}
onChange={[Function]}
setByEnv={false}
type="input"
value="marketplace.example.com"
/>
<div
@@ -3502,7 +3493,6 @@ exports[`components/PluginManagement should match snapshot, with installed plugi
}
onChange={[Function]}
setByEnv={false}
type="input"
value="marketplace.example.com"
/>
<div
@@ -3914,7 +3904,6 @@ exports[`components/PluginManagement should match snapshot, with installed plugi
}
onChange={[Function]}
setByEnv={false}
type="input"
value="marketplace.example.com"
/>
<div
@@ -4294,7 +4283,6 @@ exports[`components/PluginManagement should match snapshot, with installed plugi
}
onChange={[Function]}
setByEnv={false}
type="input"
value="marketplace.example.com"
/>
<div
@@ -4674,7 +4662,6 @@ exports[`components/PluginManagement should match snapshot, with installed plugi
}
onChange={[Function]}
setByEnv={false}
type="input"
value="marketplace.example.com"
/>
<div
@@ -5054,7 +5041,6 @@ exports[`components/PluginManagement should match snapshot, with installed plugi
}
onChange={[Function]}
setByEnv={false}
type="input"
value="marketplace.example.com"
/>
<div

Просмотреть файл

@@ -1235,7 +1235,6 @@ export default class PluginManagement extends AdminSettings<Props, State> {
/>
<TextSetting
id={'marketplaceUrl'}
type={'input'}
label={
<FormattedMessage
id='admin.plugins.settings.marketplaceUrl'

Просмотреть файл

@@ -359,7 +359,6 @@ export default class PushSettings extends AdminSettings<Props, State> {
onChange={this.handleChange}
disabled={this.props.isDisabled || this.state.pushNotificationServerType !== PUSH_NOTIFICATIONS_CUSTOM}
setByEnv={this.isSetByEnv('EmailSettings.PushNotificationServer')}
type='input'
/>
<TextSetting
id='maxNotificationsPerChannel'

Просмотреть файл

@@ -9,24 +9,22 @@ import AdminTextSetting from './text_setting';
describe('components/admin_console/TextSetting', () => {
test('render component with required props', () => {
const onChange = jest.fn();
renderWithIntl(
<AdminTextSetting
id='string.id'
id='some.id'
label='some label'
value='some value'
onChange={onChange}
onChange={jest.fn()}
setByEnv={false}
labelClassName=''
inputClassName=''
maxLength={-1}
resizable={true}
type='input'
/>,
);
screen.getByText('some label', {exact: false});
expect(screen.getByTestId('string.idinput')).toHaveProperty('id', 'string.id');
expect(screen.getByTestId('string.idinput')).toHaveValue('some value');
expect(screen.getByTestId('some.idinput')).toHaveProperty('id', 'some.id');
expect(screen.getByTestId('some.idinput')).toHaveValue('some value');
});
});

Просмотреть файл

@@ -3,7 +3,7 @@
import React from 'react';
import TextSetting, {WidgetTextSettingProps} from 'components/widgets/settings/text_setting';
import TextSetting, {Props as WidgetTextSettingProps} from 'components/widgets/settings/text_setting';
import SetByEnv from './set_by_env';

Просмотреть файл

@@ -8,8 +8,6 @@ import {AppField} from '@mattermost/types/apps';
import TextSetting from 'components/widgets/settings/text_setting';
import Markdown from 'components/markdown';
import AppsFormField, {Props} from './apps_form_field';
import AppsFormSelectField from './apps_form_select_field';
@@ -37,23 +35,6 @@ describe('components/apps_form/apps_form_field/AppsFormField', () => {
performLookup: jest.fn(),
};
const baseTextSettingProps = {
inputClassName: '',
label: (
<React.Fragment>
{textField.modal_label}
{false}
</React.Fragment>
),
maxLength: 100,
placeholder: 'The hint',
resizable: false,
type: 'input',
value: '',
id: baseDialogTextProps.name,
helpText: (<Markdown message='The description'/>),
};
it('subtype blank - optional field', () => {
const wrapper = shallow(
<AppsFormField
@@ -65,18 +46,8 @@ describe('components/apps_form/apps_form_field/AppsFormField', () => {
}}
/>,
);
expect(wrapper.matchesElement(
<TextSetting
{...baseTextSettingProps}
label={(
<React.Fragment>
{textField.modal_label}
{<span className='light'>{' (optional)'}</span>}
</React.Fragment>
)}
type='input'
/>,
)).toEqual(true);
expect(wrapper.find(TextSetting).props().type).toEqual('text');
});
it('subtype blank', () => {
@@ -86,12 +57,7 @@ describe('components/apps_form/apps_form_field/AppsFormField', () => {
/>,
);
expect(wrapper.matchesElement(
<TextSetting
{...baseTextSettingProps}
type='input'
/>,
)).toEqual(true);
expect(wrapper.find(TextSetting).props().type).toEqual('text');
});
it('subtype email', () => {
@@ -104,30 +70,8 @@ describe('components/apps_form/apps_form_field/AppsFormField', () => {
}}
/>,
);
expect(wrapper.matchesElement(
<TextSetting
{...baseTextSettingProps}
type='email'
/>,
)).toEqual(true);
});
it('subtype invalid', () => {
const wrapper = shallow(
<AppsFormField
{...baseDialogTextProps}
field={{
...textField,
subtype: 'invalid',
}}
/>,
);
expect(wrapper.matchesElement(
<TextSetting
{...baseTextSettingProps}
type='input'
/>,
)).toEqual(true);
expect(wrapper.find(TextSetting).props().type).toEqual('email');
});
it('subtype password', () => {
@@ -140,12 +84,8 @@ describe('components/apps_form/apps_form_field/AppsFormField', () => {
}}
/>,
);
expect(wrapper.matchesElement(
<TextSetting
{...baseTextSettingProps}
type='password'
/>,
)).toEqual(true);
expect(wrapper.find(TextSetting).props().type).toEqual('password');
});
});

Просмотреть файл

@@ -108,18 +108,13 @@ export default class AppsFormField extends React.PureComponent<Props> {
}
}
let textType: InputTypes = 'input';
if (subtype && TextSetting.validTypes.includes(subtype)) {
textType = subtype as InputTypes;
}
const textValue = value as string;
return (
<TextSetting
autoFocus={this.props.autoFocus}
id={name}
disabled={field.readonly}
type={textType}
type={subtype as InputTypes}
label={displayNameContent}
maxLength={maxLength}
value={textValue || ''}

Просмотреть файл

@@ -21,18 +21,7 @@ describe('components/interactive_dialog/DialogElement', () => {
},
onChange: jest.fn(),
};
const baseTextSettingProps = {
id: baseDialogProps.name,
maxLength: 100,
resizable: false,
value: '',
label: (
<React.Fragment>
{baseDialogProps.displayName}
<span className='error-text'>{' *'}</span>
</React.Fragment>
),
};
it('subtype blank', () => {
const wrapper = shallow(
<DialogElement
@@ -40,12 +29,8 @@ describe('components/interactive_dialog/DialogElement', () => {
subtype=''
/>,
);
expect(wrapper.matchesElement(
<TextSetting
{...baseTextSettingProps}
type='input'
/>,
)).toEqual(true);
expect(wrapper.find(TextSetting).props().type).toEqual('text');
});
it('subtype email', () => {
@@ -55,27 +40,7 @@ describe('components/interactive_dialog/DialogElement', () => {
subtype='email'
/>,
);
expect(wrapper.matchesElement(
<TextSetting
{...baseTextSettingProps}
type='email'
/>,
)).toEqual(true);
});
it('subtype invalid', () => {
const wrapper = shallow(
<DialogElement
{...baseDialogProps}
subtype='invalid'
/>,
);
expect(wrapper.matchesElement(
<TextSetting
{...baseTextSettingProps}
type='input'
/>,
)).toEqual(true);
expect(wrapper.find(TextSetting).props().type).toEqual('email');
});
it('subtype password', () => {
@@ -85,12 +50,7 @@ describe('components/interactive_dialog/DialogElement', () => {
subtype='password'
/>,
);
expect(wrapper.matchesElement(
<TextSetting
{...baseTextSettingProps}
type='password'
/>,
)).toEqual(true);
expect(wrapper.find(TextSetting).props().type).toEqual('password');
});
describe('radioSetting', () => {

Просмотреть файл

@@ -116,10 +116,10 @@ export default class DialogElement extends React.PureComponent<Props, State> {
errorText,
optional,
options,
type,
maxLength,
} = this.props;
let {type, maxLength} = this.props;
let displayNameContent: React.ReactNode = displayName;
if (optional) {
displayNameContent = (
@@ -155,16 +155,11 @@ export default class DialogElement extends React.PureComponent<Props, State> {
}
if (type === 'text' || type === 'textarea') {
let textSettingMaxLength;
if (type === 'text') {
maxLength = maxLength || TEXT_DEFAULT_MAX_LENGTH;
if (subtype && TextSetting.validTypes.includes(subtype)) {
type = subtype;
} else {
type = 'input';
}
textSettingMaxLength = maxLength || TEXT_DEFAULT_MAX_LENGTH;
} else {
maxLength = maxLength || TEXTAREA_DEFAULT_MAX_LENGTH;
textSettingMaxLength = maxLength || TEXTAREA_DEFAULT_MAX_LENGTH;
}
const textValue = value as string;
@@ -172,9 +167,9 @@ export default class DialogElement extends React.PureComponent<Props, State> {
<TextSetting
autoFocus={this.props.autoFocus}
id={name}
type={type as InputTypes}
type={subtype as InputTypes || 'text'}
label={displayNameContent}
maxLength={maxLength}
maxLength={textSettingMaxLength}
value={textValue || ''}
placeholder={placeholder}
helpText={helpTextContent}

Просмотреть файл

@@ -0,0 +1,40 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`components/widgets/settings/TextSetting render component with required props 1`] = `
<Setting
inputClassName=""
inputId="string.id"
label="some label"
labelClassName=""
>
<input
className="form-control"
data-testid="string.idinput"
id="string.id"
maxLength={-1}
onChange={[Function]}
type="text"
value="some value"
/>
</Setting>
`;
exports[`components/widgets/settings/TextSetting render with textarea type 1`] = `
<Setting
inputClassName=""
inputId="string.id"
label="some label"
labelClassName=""
>
<textarea
className="form-control"
data-testid="string.idinput"
dir="auto"
id="string.id"
maxLength={-1}
onChange={[Function]}
rows={5}
value="some value"
/>
</Setting>
`;

Просмотреть файл

@@ -17,24 +17,8 @@ describe('components/widgets/settings/TextSetting', () => {
onChange={onChange}
/>,
);
expect(wrapper).toMatchInlineSnapshot(`
<Setting
inputClassName=""
inputId="string.id"
label="some label"
labelClassName=""
>
<input
className="form-control"
data-testid="string.idinput"
id="string.id"
maxLength={-1}
onChange={[Function]}
type="input"
value="some value"
/>
</Setting>
`);
expect(wrapper).toMatchSnapshot();
});
test('render with textarea type', () => {
@@ -48,26 +32,8 @@ describe('components/widgets/settings/TextSetting', () => {
onChange={onChange}
/>,
);
expect(wrapper).toMatchInlineSnapshot(`
<Setting
inputClassName=""
inputId="string.id"
label="some label"
labelClassName=""
>
<textarea
className="form-control"
data-testid="string.idinput"
dir="auto"
id="string.id"
maxLength={-1}
onChange={[Function]}
rows={5}
style={Object {}}
value="some value"
/>
</Setting>
`);
expect(wrapper).toMatchSnapshot();
});
test('onChange', () => {

Просмотреть файл

@@ -1,108 +1,95 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import React, {ChangeEvent, ReactNode} from 'react';
import Setting from './setting';
export type InputTypes = 'input' | 'textarea' | 'number' | 'email' | 'tel' | 'url' | 'password'
const INPUT_TYPES = ['text', 'textarea', 'number', 'email', 'tel', 'url', 'password'] as const;
export type InputTypes = typeof INPUT_TYPES[number];
export type WidgetTextSettingProps = {
export type Props = {
id: string;
label: React.ReactNode;
label: ReactNode;
labelClassName?: string;
placeholder?: string;
helpText?: React.ReactNode;
footer?: React.ReactNode;
helpText?: ReactNode;
footer?: ReactNode;
value: string | number;
inputClassName?: string;
maxLength?: number;
resizable?: boolean;
onChange(name: string, value: any): void;
onChange(id: string, value: any): void;
disabled?: boolean;
type: InputTypes;
// This is a custom prop that is not part of the HTML input element type
type?: InputTypes;
autoFocus?: boolean;
}
// Since handle change is read from input and textarea element
type HandleChangeTypes = React.ChangeEventHandler<HTMLInputElement | HTMLTextAreaElement>
function TextSetting(props: Props) {
const {labelClassName = '', inputClassName = '', maxLength = -1, resizable = true, type = 'text'} = props;
export default class TextSetting extends React.PureComponent<WidgetTextSettingProps> {
public static validTypes: string[] = ['input', 'textarea', 'number', 'email', 'tel', 'url', 'password'];
public static defaultProps: Partial<WidgetTextSettingProps> = {
labelClassName: '',
inputClassName: '',
type: 'input',
maxLength: -1, // A negative number allows for values of any length
resizable: true,
};
private handleChange: HandleChangeTypes = (e) => {
if (this.props.type === 'number') {
this.props.onChange(this.props.id, parseInt(e.target.value, 10));
function handleChange(event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) {
if (props.type === 'number') {
props.onChange(props.id, parseInt(event.target.value, 10));
} else {
this.props.onChange(this.props.id, e.target.value);
props.onChange(props.id, event.target.value);
}
};
}
public render(): JSX.Element {
const {resizable} = this.props;
let {type} = this.props;
let input = null;
let input = null;
if (type === 'textarea') {
input = (
<textarea
id={props.id}
data-testid={`${props.id}input`} // a lot of our e2e test rely on 'input' being in the test id if it's a text/textarea input
className='form-control'
autoFocus={props.autoFocus}
dir='auto'
rows={5}
placeholder={props.placeholder}
style={resizable === false ? {resize: 'none'} : undefined}
value={props.value}
maxLength={maxLength}
onChange={handleChange}
disabled={props.disabled}
/>
);
} else {
const inputType = INPUT_TYPES.includes(type) ? type : 'text';
if (type === 'textarea') {
let style = {};
if (!resizable) {
style = Object.assign({}, {resize: 'none'});
}
// a lot of our e2e test rely on 'input' being in the test id if it's a text/textarea input
const testId = inputType === 'text' ? `${props.id}input` : `${props.id}${inputType}`;
input = (
<textarea
autoFocus={this.props.autoFocus}
data-testid={this.props.id + 'input'}
id={this.props.id}
dir='auto'
style={style}
className='form-control'
rows={5}
placeholder={this.props.placeholder}
value={this.props.value}
maxLength={this.props.maxLength}
onChange={this.handleChange}
disabled={this.props.disabled}
/>
);
} else {
type = ['input', 'email', 'tel', 'number', 'url', 'password'].includes(type) ? type : 'input';
input = (
<input
autoFocus={this.props.autoFocus}
data-testid={this.props.id + type}
id={this.props.id}
className='form-control'
type={type}
placeholder={this.props.placeholder}
value={this.props.value}
maxLength={this.props.maxLength}
onChange={this.handleChange}
disabled={this.props.disabled}
/>
);
}
return (
<Setting
label={this.props.label}
labelClassName={this.props.labelClassName}
inputClassName={this.props.inputClassName}
helpText={this.props.helpText}
inputId={this.props.id}
footer={this.props.footer}
>
{input}
</Setting>
input = (
<input
id={props.id}
data-testid={testId}
className='form-control'
autoFocus={props.autoFocus}
type={inputType}
placeholder={props.placeholder}
value={props.value}
maxLength={maxLength}
onChange={handleChange}
disabled={props.disabled}
/>
);
}
return (
<Setting
label={props.label}
labelClassName={labelClassName}
inputClassName={inputClassName}
helpText={props.helpText}
inputId={props.id}
footer={props.footer}
>
{input}
</Setting>
);
}
export default TextSetting;