[MM-47090]: Migrate "components/integrations/abstract_command.jsx" to Typescript (#23325)
Этот коммит содержится в:
@@ -43,7 +43,7 @@ exports[`components/integrations/AbstractCommand should match snapshot 1`] = `
|
||||
<input
|
||||
className="form-control"
|
||||
id="displayName"
|
||||
maxLength="64"
|
||||
maxLength={64}
|
||||
onChange={[Function]}
|
||||
type="text"
|
||||
value="display_name"
|
||||
@@ -76,7 +76,7 @@ exports[`components/integrations/AbstractCommand should match snapshot 1`] = `
|
||||
<input
|
||||
className="form-control"
|
||||
id="description"
|
||||
maxLength="128"
|
||||
maxLength={128}
|
||||
onChange={[Function]}
|
||||
type="text"
|
||||
value="description"
|
||||
@@ -177,7 +177,7 @@ exports[`components/integrations/AbstractCommand should match snapshot 1`] = `
|
||||
<LocalizedInput
|
||||
className="form-control"
|
||||
id="url"
|
||||
maxLength="1024"
|
||||
maxLength={1024}
|
||||
onChange={[Function]}
|
||||
placeholder={
|
||||
Object {
|
||||
@@ -258,7 +258,7 @@ exports[`components/integrations/AbstractCommand should match snapshot 1`] = `
|
||||
<LocalizedInput
|
||||
className="form-control"
|
||||
id="username"
|
||||
maxLength="64"
|
||||
maxLength={64}
|
||||
onChange={[Function]}
|
||||
placeholder={
|
||||
Object {
|
||||
@@ -297,7 +297,7 @@ exports[`components/integrations/AbstractCommand should match snapshot 1`] = `
|
||||
<LocalizedInput
|
||||
className="form-control"
|
||||
id="iconUrl"
|
||||
maxLength="1024"
|
||||
maxLength={1024}
|
||||
onChange={[Function]}
|
||||
placeholder={
|
||||
Object {
|
||||
@@ -367,7 +367,7 @@ exports[`components/integrations/AbstractCommand should match snapshot 1`] = `
|
||||
<LocalizedInput
|
||||
className="form-control"
|
||||
id="autocompleteHint"
|
||||
maxLength="1024"
|
||||
maxLength={1024}
|
||||
onChange={[Function]}
|
||||
placeholder={
|
||||
Object {
|
||||
@@ -406,7 +406,7 @@ exports[`components/integrations/AbstractCommand should match snapshot 1`] = `
|
||||
<LocalizedInput
|
||||
className="form-control"
|
||||
id="description"
|
||||
maxLength="128"
|
||||
maxLength={128}
|
||||
onChange={[Function]}
|
||||
placeholder={
|
||||
Object {
|
||||
@@ -462,7 +462,9 @@ exports[`components/integrations/AbstractCommand should match snapshot 1`] = `
|
||||
id="Footer"
|
||||
/>
|
||||
</SpinnerButton>
|
||||
renderExtra
|
||||
<div>
|
||||
renderExtra
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -512,7 +514,7 @@ exports[`components/integrations/AbstractCommand should match snapshot, displays
|
||||
<input
|
||||
className="form-control"
|
||||
id="displayName"
|
||||
maxLength="64"
|
||||
maxLength={64}
|
||||
onChange={[Function]}
|
||||
type="text"
|
||||
value="display_name"
|
||||
@@ -545,7 +547,7 @@ exports[`components/integrations/AbstractCommand should match snapshot, displays
|
||||
<input
|
||||
className="form-control"
|
||||
id="description"
|
||||
maxLength="128"
|
||||
maxLength={128}
|
||||
onChange={[Function]}
|
||||
type="text"
|
||||
value="description"
|
||||
@@ -646,7 +648,7 @@ exports[`components/integrations/AbstractCommand should match snapshot, displays
|
||||
<LocalizedInput
|
||||
className="form-control"
|
||||
id="url"
|
||||
maxLength="1024"
|
||||
maxLength={1024}
|
||||
onChange={[Function]}
|
||||
placeholder={
|
||||
Object {
|
||||
@@ -727,7 +729,7 @@ exports[`components/integrations/AbstractCommand should match snapshot, displays
|
||||
<LocalizedInput
|
||||
className="form-control"
|
||||
id="username"
|
||||
maxLength="64"
|
||||
maxLength={64}
|
||||
onChange={[Function]}
|
||||
placeholder={
|
||||
Object {
|
||||
@@ -766,7 +768,7 @@ exports[`components/integrations/AbstractCommand should match snapshot, displays
|
||||
<LocalizedInput
|
||||
className="form-control"
|
||||
id="iconUrl"
|
||||
maxLength="1024"
|
||||
maxLength={1024}
|
||||
onChange={[Function]}
|
||||
placeholder={
|
||||
Object {
|
||||
@@ -836,7 +838,7 @@ exports[`components/integrations/AbstractCommand should match snapshot, displays
|
||||
<LocalizedInput
|
||||
className="form-control"
|
||||
id="autocompleteHint"
|
||||
maxLength="1024"
|
||||
maxLength={1024}
|
||||
onChange={[Function]}
|
||||
placeholder={
|
||||
Object {
|
||||
@@ -875,7 +877,7 @@ exports[`components/integrations/AbstractCommand should match snapshot, displays
|
||||
<LocalizedInput
|
||||
className="form-control"
|
||||
id="description"
|
||||
maxLength="128"
|
||||
maxLength={128}
|
||||
onChange={[Function]}
|
||||
placeholder={
|
||||
Object {
|
||||
@@ -934,7 +936,9 @@ exports[`components/integrations/AbstractCommand should match snapshot, displays
|
||||
id="Footer"
|
||||
/>
|
||||
</SpinnerButton>
|
||||
renderExtra
|
||||
<div>
|
||||
renderExtra
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -1,16 +1,18 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import React, {FormEvent} from 'react';
|
||||
import {shallow} from 'enzyme';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
|
||||
import AbstractCommand from 'components/integrations/abstract_command.jsx';
|
||||
import AbstractCommand from 'components/integrations/abstract_command';
|
||||
import {TestHelper} from 'utils/test_helper';
|
||||
|
||||
describe('components/integrations/AbstractCommand', () => {
|
||||
const header = {id: 'Header', defaultMessage: 'Header'};
|
||||
const footer = {id: 'Footer', defaultMessage: 'Footer'};
|
||||
const loading = {id: 'Loading', defaultMessage: 'Loading'};
|
||||
const method: 'G' | 'P' | '' = 'G';
|
||||
const command = {
|
||||
id: 'r5tpgt4iepf45jt768jz84djic',
|
||||
display_name: 'display_name',
|
||||
@@ -20,23 +22,21 @@ describe('components/integrations/AbstractCommand', () => {
|
||||
auto_complete_hint: 'auto_complete_hint',
|
||||
auto_complete_desc: 'auto_complete_desc',
|
||||
token: 'jb6oyqh95irpbx8fo9zmndkp1r',
|
||||
create_at: '1499722850203',
|
||||
create_at: 1499722850203,
|
||||
creator_id: '88oybd1dwfdoxpkpw1h5kpbyco',
|
||||
delete_at: 0,
|
||||
icon_url: 'https://google.com/icon',
|
||||
method: 'G',
|
||||
method,
|
||||
team_id: 'm5gix3oye3du8ghk4ko6h9cq7y',
|
||||
update_at: 1504468859001,
|
||||
url: 'https://google.com/command',
|
||||
username: 'username',
|
||||
};
|
||||
const team = {
|
||||
name: 'test',
|
||||
id: command.team_id,
|
||||
};
|
||||
const team = TestHelper.getTeamMock({name: 'test', id: command.team_id});
|
||||
|
||||
const action = jest.fn().mockImplementation(
|
||||
() => {
|
||||
return new Promise((resolve) => {
|
||||
return new Promise<void>((resolve) => {
|
||||
process.nextTick(() => resolve());
|
||||
});
|
||||
},
|
||||
@@ -47,14 +47,14 @@ describe('components/integrations/AbstractCommand', () => {
|
||||
header,
|
||||
footer,
|
||||
loading,
|
||||
renderExtra: 'renderExtra',
|
||||
renderExtra: <div>{'renderExtra'}</div>,
|
||||
serverError: '',
|
||||
initialCommand: command,
|
||||
action,
|
||||
};
|
||||
|
||||
test('should match snapshot', () => {
|
||||
const wrapper = shallow(
|
||||
const wrapper = shallow<AbstractCommand>(
|
||||
<AbstractCommand {...baseProps}/>,
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
@@ -63,7 +63,7 @@ describe('components/integrations/AbstractCommand', () => {
|
||||
test('should match snapshot, displays client error', () => {
|
||||
const newSeverError = 'server error';
|
||||
const props = {...baseProps, serverError: newSeverError};
|
||||
const wrapper = shallow(
|
||||
const wrapper = shallow<AbstractCommand>(
|
||||
<AbstractCommand {...props}/>,
|
||||
);
|
||||
|
||||
@@ -75,7 +75,7 @@ describe('components/integrations/AbstractCommand', () => {
|
||||
});
|
||||
|
||||
test('should call action function', () => {
|
||||
const wrapper = shallow(
|
||||
const wrapper = shallow<AbstractCommand>(
|
||||
<AbstractCommand {...baseProps}/>,
|
||||
);
|
||||
|
||||
@@ -86,7 +86,7 @@ describe('components/integrations/AbstractCommand', () => {
|
||||
});
|
||||
|
||||
test('should match object returned by getStateFromCommand', () => {
|
||||
const wrapper = shallow(
|
||||
const wrapper = shallow<AbstractCommand>(
|
||||
<AbstractCommand {...baseProps}/>,
|
||||
);
|
||||
|
||||
@@ -109,67 +109,77 @@ describe('components/integrations/AbstractCommand', () => {
|
||||
});
|
||||
|
||||
test('should match state when method is called', () => {
|
||||
const wrapper = shallow(
|
||||
const wrapper = shallow<AbstractCommand>(
|
||||
<AbstractCommand {...baseProps}/>,
|
||||
);
|
||||
|
||||
const displayName = 'new display_name';
|
||||
wrapper.instance().updateDisplayName({target: {value: displayName}});
|
||||
const displayNameEvent = {preventDefault: jest.fn(), target: {value: displayName}} as any;
|
||||
wrapper.instance().updateDisplayName(displayNameEvent);
|
||||
expect(wrapper.state('displayName')).toEqual(displayName);
|
||||
|
||||
const description = 'new description';
|
||||
wrapper.instance().updateDescription({target: {value: description}});
|
||||
const descriptionEvent = {preventDefault: jest.fn(), target: {value: description}} as any;
|
||||
wrapper.instance().updateDescription(descriptionEvent);
|
||||
expect(wrapper.state('description')).toEqual(description);
|
||||
|
||||
const trigger = 'new trigger';
|
||||
wrapper.instance().updateTrigger({target: {value: trigger}});
|
||||
const triggerEvent = {preventDefault: jest.fn(), target: {value: trigger}} as any;
|
||||
wrapper.instance().updateTrigger(triggerEvent);
|
||||
expect(wrapper.state('trigger')).toEqual(trigger);
|
||||
|
||||
const url = 'new url';
|
||||
wrapper.instance().updateUrl({target: {value: url}});
|
||||
const urlEvent = {preventDefault: jest.fn(), target: {value: url}} as any;
|
||||
wrapper.instance().updateUrl(urlEvent);
|
||||
expect(wrapper.state('url')).toEqual(url);
|
||||
|
||||
const method = 'new method';
|
||||
wrapper.instance().updateMethod({target: {value: method}});
|
||||
const method = 'P';
|
||||
const methodEvent = {preventDefault: jest.fn(), target: {value: method}} as any;
|
||||
wrapper.instance().updateMethod(methodEvent);
|
||||
expect(wrapper.state('method')).toEqual(method);
|
||||
|
||||
const username = 'new username';
|
||||
wrapper.instance().updateUsername({target: {value: username}});
|
||||
const usernameEvent = {preventDefault: jest.fn(), target: {value: username}} as any;
|
||||
wrapper.instance().updateUsername(usernameEvent);
|
||||
expect(wrapper.state('username')).toEqual(username);
|
||||
|
||||
const iconUrl = 'new iconUrl';
|
||||
wrapper.instance().updateIconUrl({target: {value: iconUrl}});
|
||||
const iconUrlEvent = {preventDefault: jest.fn(), target: {value: iconUrl}} as any;
|
||||
wrapper.instance().updateIconUrl(iconUrlEvent);
|
||||
expect(wrapper.state('iconUrl')).toEqual(iconUrl);
|
||||
|
||||
wrapper.instance().updateAutocomplete({target: {checked: true}});
|
||||
const trueUpdateAutocompleteEvent = {target: {checked: true}} as any;
|
||||
const falseeUpdateAutocompleteEvent = {target: {checked: false}} as any;
|
||||
wrapper.instance().updateAutocomplete(trueUpdateAutocompleteEvent);
|
||||
expect(wrapper.state('autocomplete')).toEqual(true);
|
||||
wrapper.instance().updateAutocomplete({target: {checked: false}});
|
||||
wrapper.instance().updateAutocomplete(falseeUpdateAutocompleteEvent);
|
||||
expect(wrapper.state('autocomplete')).toEqual(false);
|
||||
|
||||
const autocompleteHint = 'new autocompleteHint';
|
||||
wrapper.instance().updateAutocompleteHint({target: {value: autocompleteHint}});
|
||||
const autocompleteHintEvent = {preventDefault: jest.fn(), target: {value: autocompleteHint}} as any;
|
||||
wrapper.instance().updateAutocompleteHint(autocompleteHintEvent);
|
||||
expect(wrapper.state('autocompleteHint')).toEqual(autocompleteHint);
|
||||
|
||||
const autocompleteDescription = 'new autocompleteDescription';
|
||||
wrapper.instance().updateAutocompleteDescription({target: {value: autocompleteDescription}});
|
||||
const autocompleteDescriptionEvent = {preventDefault: jest.fn(), target: {value: autocompleteDescription}} as any;
|
||||
wrapper.instance().updateAutocompleteDescription(autocompleteDescriptionEvent);
|
||||
expect(wrapper.state('autocompleteDescription')).toEqual(autocompleteDescription);
|
||||
});
|
||||
|
||||
test('should match state when handleSubmit is called', () => {
|
||||
const newAction = jest.fn().mockImplementation(
|
||||
() => {
|
||||
return new Promise((resolve) => {
|
||||
return new Promise<void>((resolve) => {
|
||||
process.nextTick(() => resolve());
|
||||
});
|
||||
},
|
||||
);
|
||||
const props = {...baseProps, action: newAction};
|
||||
const wrapper = shallow(
|
||||
const wrapper = shallow<AbstractCommand>(
|
||||
<AbstractCommand {...props}/>,
|
||||
);
|
||||
expect(newAction).toHaveBeenCalledTimes(0);
|
||||
|
||||
const evt = {preventDefault: jest.fn()};
|
||||
const evt = {preventDefault: jest.fn()} as unknown as FormEvent<Element>;
|
||||
const handleSubmit = wrapper.instance().handleSubmit;
|
||||
handleSubmit(evt);
|
||||
expect(wrapper.state('saving')).toEqual(true);
|
||||
@@ -1,9 +1,9 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
import React, {ChangeEvent} from 'react';
|
||||
import {FormattedMessage, MessageDescriptor} from 'react-intl';
|
||||
|
||||
import {Link} from 'react-router-dom';
|
||||
|
||||
import BackstageHeader from 'components/backstage/components/backstage_header';
|
||||
@@ -12,81 +12,98 @@ import * as Utils from 'utils/utils';
|
||||
import FormError from 'components/form_error';
|
||||
import SpinnerButton from 'components/spinner_button';
|
||||
import LocalizedInput from 'components/localized_input/localized_input';
|
||||
import ExternalLink from 'components/external_link';
|
||||
|
||||
import {t} from 'utils/i18n';
|
||||
import ExternalLink from 'components/external_link';
|
||||
import {Command} from '@mattermost/types/integrations';
|
||||
import {Team} from '@mattermost/types/teams';
|
||||
|
||||
const REQUEST_POST = 'P';
|
||||
const REQUEST_GET = 'G';
|
||||
|
||||
export default class AbstractCommand extends React.PureComponent {
|
||||
static propTypes = {
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* The current team
|
||||
*/
|
||||
team: PropTypes.object.isRequired,
|
||||
/**
|
||||
* The current team
|
||||
*/
|
||||
team: Team;
|
||||
|
||||
/**
|
||||
* The header text to render, has id and defaultMessage
|
||||
*/
|
||||
header: PropTypes.object.isRequired,
|
||||
/**
|
||||
* The header text to render, has id and defaultMessage
|
||||
*/
|
||||
header: MessageDescriptor;
|
||||
|
||||
/**
|
||||
* The footer text to render, has id and defaultMessage
|
||||
*/
|
||||
footer: PropTypes.object.isRequired,
|
||||
/**
|
||||
* The footer text to render, has id and defaultMessage
|
||||
*/
|
||||
footer: MessageDescriptor;
|
||||
|
||||
/**
|
||||
* The spinner loading text to render, has id and defaultMessage
|
||||
*/
|
||||
loading: PropTypes.object.isRequired,
|
||||
/**
|
||||
* The spinner loading text to render, has id and defaultMessage
|
||||
*/
|
||||
loading: MessageDescriptor;
|
||||
|
||||
/**
|
||||
* Any extra component/node to render
|
||||
*/
|
||||
renderExtra: PropTypes.node.isRequired,
|
||||
/**
|
||||
* Any extra component/node to render
|
||||
*/
|
||||
renderExtra?: JSX.Element;
|
||||
|
||||
/**
|
||||
* The server error text after a failed action
|
||||
*/
|
||||
serverError: PropTypes.string.isRequired,
|
||||
/**
|
||||
* The server error text after a failed action
|
||||
*/
|
||||
serverError: string;
|
||||
|
||||
/**
|
||||
* The Command used to set the initial state
|
||||
*/
|
||||
initialCommand: PropTypes.object,
|
||||
/**
|
||||
* The Command used to set the initial state
|
||||
*/
|
||||
initialCommand?: Partial<Command>;
|
||||
|
||||
/**
|
||||
* The async function to run when the action button is pressed
|
||||
*/
|
||||
action: PropTypes.func.isRequired,
|
||||
};
|
||||
/**
|
||||
* The async function to run when the action button is pressed
|
||||
*/
|
||||
action: (command: Command) => Promise<void>;
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
type State= {
|
||||
saving: boolean;
|
||||
clientError: null | JSX.Element | string;
|
||||
trigger: string;
|
||||
displayName: string;
|
||||
description: string;
|
||||
url: string;
|
||||
method: 'P' | 'G' | '';
|
||||
username: string;
|
||||
iconUrl: string;
|
||||
autocomplete: boolean;
|
||||
autocompleteHint: string;
|
||||
autocompleteDescription: string;
|
||||
}
|
||||
|
||||
export default class AbstractCommand extends React.PureComponent<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = this.getStateFromCommand(this.props.initialCommand || {});
|
||||
}
|
||||
|
||||
getStateFromCommand = (command) => {
|
||||
getStateFromCommand = (command: Props['initialCommand']) => {
|
||||
return {
|
||||
displayName: command.display_name || '',
|
||||
description: command.description || '',
|
||||
trigger: command.trigger || '',
|
||||
url: command.url || '',
|
||||
method: command.method || REQUEST_POST,
|
||||
username: command.username || '',
|
||||
iconUrl: command.icon_url || '',
|
||||
autocomplete: command.auto_complete || false,
|
||||
autocompleteHint: command.auto_complete_hint || '',
|
||||
autocompleteDescription: command.auto_complete_desc || '',
|
||||
displayName: command?.display_name ?? '',
|
||||
description: command?.description ?? '',
|
||||
trigger: command?.trigger ?? '',
|
||||
url: command?.url ?? '',
|
||||
method: command?.method ?? REQUEST_POST,
|
||||
username: command?.username ?? '',
|
||||
iconUrl: command?.icon_url ?? '',
|
||||
autocomplete: command?.auto_complete ?? false,
|
||||
autocompleteHint: command?.auto_complete_hint ?? '',
|
||||
autocompleteDescription: command?.auto_complete_desc ?? '',
|
||||
saving: false,
|
||||
clientError: null,
|
||||
};
|
||||
};
|
||||
|
||||
handleSubmit = (e) => {
|
||||
handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
if (this.state.saving) {
|
||||
@@ -113,11 +130,19 @@ export default class AbstractCommand extends React.PureComponent {
|
||||
icon_url: this.state.iconUrl,
|
||||
auto_complete: this.state.autocomplete,
|
||||
team_id: this.props.team.id,
|
||||
auto_complete_desc: '',
|
||||
auto_complete_hint: '',
|
||||
token: '',
|
||||
create_at: 0,
|
||||
update_at: 0,
|
||||
delete_at: 0,
|
||||
id: '',
|
||||
creator_id: '',
|
||||
};
|
||||
|
||||
if (command.auto_complete) {
|
||||
command.auto_complete_desc = this.state.autocompleteDescription;
|
||||
command.auto_complete_hint = this.state.autocompleteHint;
|
||||
command.auto_complete_desc = this.state.autocompleteDescription ?? '';
|
||||
command.auto_complete_hint = this.state.autocompleteHint ?? '';
|
||||
}
|
||||
|
||||
if (!command.trigger) {
|
||||
@@ -197,61 +222,64 @@ export default class AbstractCommand extends React.PureComponent {
|
||||
this.props.action(command).then(() => this.setState({saving: false}));
|
||||
};
|
||||
|
||||
updateDisplayName = (e) => {
|
||||
updateDisplayName = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
this.setState({
|
||||
displayName: e.target.value,
|
||||
});
|
||||
};
|
||||
|
||||
updateDescription = (e) => {
|
||||
updateDescription = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
this.setState({
|
||||
description: e.target.value,
|
||||
});
|
||||
};
|
||||
|
||||
updateTrigger = (e) => {
|
||||
updateTrigger = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
this.setState({
|
||||
trigger: e.target.value,
|
||||
});
|
||||
};
|
||||
|
||||
updateUrl = (e) => {
|
||||
updateUrl = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
this.setState({
|
||||
url: e.target.value,
|
||||
});
|
||||
};
|
||||
|
||||
updateMethod = (e) => {
|
||||
this.setState({
|
||||
method: e.target.value,
|
||||
});
|
||||
updateMethod = (e: ChangeEvent<HTMLSelectElement>) => {
|
||||
const methodValue = e.target.value;
|
||||
if (methodValue === 'P' || methodValue === 'G' || methodValue === '') {
|
||||
this.setState({
|
||||
method: methodValue,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
updateUsername = (e) => {
|
||||
updateUsername = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
this.setState({
|
||||
username: e.target.value,
|
||||
});
|
||||
};
|
||||
|
||||
updateIconUrl = (e) => {
|
||||
updateIconUrl = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
this.setState({
|
||||
iconUrl: e.target.value,
|
||||
});
|
||||
};
|
||||
|
||||
updateAutocomplete = (e) => {
|
||||
updateAutocomplete = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
this.setState({
|
||||
autocomplete: e.target.checked,
|
||||
});
|
||||
};
|
||||
|
||||
updateAutocompleteHint = (e) => {
|
||||
updateAutocompleteHint = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
this.setState({
|
||||
autocompleteHint: e.target.value,
|
||||
});
|
||||
};
|
||||
|
||||
updateAutocompleteDescription = (e) => {
|
||||
updateAutocompleteDescription = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
this.setState({
|
||||
autocompleteDescription: e.target.value,
|
||||
});
|
||||
@@ -277,7 +305,7 @@ export default class AbstractCommand extends React.PureComponent {
|
||||
<LocalizedInput
|
||||
id='autocompleteHint'
|
||||
type='text'
|
||||
maxLength='1024'
|
||||
maxLength={1024}
|
||||
className='form-control'
|
||||
value={this.state.autocompleteHint}
|
||||
onChange={this.updateAutocompleteHint}
|
||||
@@ -308,7 +336,7 @@ export default class AbstractCommand extends React.PureComponent {
|
||||
<LocalizedInput
|
||||
id='description'
|
||||
type='text'
|
||||
maxLength='128'
|
||||
maxLength={128}
|
||||
className='form-control'
|
||||
value={this.state.autocompleteDescription}
|
||||
onChange={this.updateAutocompleteDescription}
|
||||
@@ -358,7 +386,7 @@ export default class AbstractCommand extends React.PureComponent {
|
||||
<input
|
||||
id='displayName'
|
||||
type='text'
|
||||
maxLength='64'
|
||||
maxLength={64}
|
||||
className='form-control'
|
||||
value={this.state.displayName}
|
||||
onChange={this.updateDisplayName}
|
||||
@@ -385,7 +413,7 @@ export default class AbstractCommand extends React.PureComponent {
|
||||
<input
|
||||
id='description'
|
||||
type='text'
|
||||
maxLength='128'
|
||||
maxLength={128}
|
||||
className='form-control'
|
||||
value={this.state.description}
|
||||
onChange={this.updateDescription}
|
||||
@@ -465,7 +493,7 @@ export default class AbstractCommand extends React.PureComponent {
|
||||
<LocalizedInput
|
||||
id='url'
|
||||
type='text'
|
||||
maxLength='1024'
|
||||
maxLength={1024}
|
||||
className='form-control'
|
||||
value={this.state.url}
|
||||
onChange={this.updateUrl}
|
||||
@@ -525,7 +553,7 @@ export default class AbstractCommand extends React.PureComponent {
|
||||
<LocalizedInput
|
||||
id='username'
|
||||
type='text'
|
||||
maxLength='64'
|
||||
maxLength={64}
|
||||
className='form-control'
|
||||
value={this.state.username}
|
||||
onChange={this.updateUsername}
|
||||
@@ -553,7 +581,7 @@ export default class AbstractCommand extends React.PureComponent {
|
||||
<LocalizedInput
|
||||
id='iconUrl'
|
||||
type='text'
|
||||
maxLength='1024'
|
||||
maxLength={1024}
|
||||
className='form-control'
|
||||
value={this.state.iconUrl}
|
||||
onChange={this.updateIconUrl}
|
||||
@@ -612,7 +640,7 @@ export default class AbstractCommand extends React.PureComponent {
|
||||
className='btn btn-primary'
|
||||
type='submit'
|
||||
spinning={this.state.saving}
|
||||
spinningText={Utils.localizeMessage(this.props.loading.id, this.props.loading.defaultMessage)}
|
||||
spinningText={Utils.localizeMessage(this.props.loading?.id ?? '', this.props.loading?.defaultMessage as string)}
|
||||
onClick={this.handleSubmit}
|
||||
id='saveCommand'
|
||||
>
|
||||
@@ -3,25 +3,9 @@
|
||||
exports[`components/integrations/AddCommand should match snapshot 1`] = `
|
||||
<AbstractCommand
|
||||
action={[Function]}
|
||||
footer={
|
||||
Object {
|
||||
"defaultMessage": "Save",
|
||||
"id": "add_command.save",
|
||||
}
|
||||
}
|
||||
header={
|
||||
Object {
|
||||
"defaultMessage": "Add",
|
||||
"id": "integrations.add",
|
||||
}
|
||||
}
|
||||
loading={
|
||||
Object {
|
||||
"defaultMessage": "Saving...",
|
||||
"id": "add_command.saving",
|
||||
}
|
||||
}
|
||||
renderExtra=""
|
||||
footer="Save"
|
||||
header="Add"
|
||||
loading="Saving..."
|
||||
serverError=""
|
||||
team={
|
||||
Object {
|
||||
|
||||
@@ -3,19 +3,14 @@
|
||||
|
||||
import React, {useState} from 'react';
|
||||
import {useHistory} from 'react-router-dom';
|
||||
import {useIntl, MessageDescriptor} from 'react-intl';
|
||||
|
||||
import {Command} from '@mattermost/types/integrations';
|
||||
import {Team} from '@mattermost/types/teams';
|
||||
|
||||
import {ActionResult} from 'mattermost-redux/types/actions.js';
|
||||
|
||||
import {t} from 'utils/i18n';
|
||||
|
||||
import AbstractCommand from '../abstract_command.jsx';
|
||||
|
||||
const HEADER = {id: t('integrations.add'), defaultMessage: 'Add'};
|
||||
const FOOTER = {id: t('add_command.save'), defaultMessage: 'Save'};
|
||||
const LOADING = {id: t('add_command.saving'), defaultMessage: 'Saving...'};
|
||||
import AbstractCommand from '../abstract_command';
|
||||
|
||||
export type Props = {
|
||||
|
||||
@@ -35,7 +30,10 @@ export type Props = {
|
||||
|
||||
const AddCommand = ({team, actions}: Props) => {
|
||||
const history = useHistory();
|
||||
|
||||
const {formatMessage} = useIntl();
|
||||
const headerMessage = formatMessage({id: ('integrations.add'), defaultMessage: 'Add'}) as MessageDescriptor;
|
||||
const footerMessage = formatMessage({id: ('add_command.save'), defaultMessage: 'Save'}) as MessageDescriptor;
|
||||
const loadingMessage = formatMessage({id: ('add_command.saving'), defaultMessage: 'Saving...'}) as MessageDescriptor;
|
||||
const [serverError, setServerError] = useState('');
|
||||
|
||||
const addCommand = async (command: Command) => {
|
||||
@@ -55,10 +53,9 @@ const AddCommand = ({team, actions}: Props) => {
|
||||
return (
|
||||
<AbstractCommand
|
||||
team={team}
|
||||
header={HEADER}
|
||||
footer={FOOTER}
|
||||
loading={LOADING}
|
||||
renderExtra={''}
|
||||
header={headerMessage}
|
||||
footer={footerMessage}
|
||||
loading={loadingMessage}
|
||||
action={addCommand}
|
||||
serverError={serverError}
|
||||
/>
|
||||
|
||||
@@ -12,7 +12,7 @@ import {getHistory} from 'utils/browser_history';
|
||||
import {t} from 'utils/i18n';
|
||||
import LoadingScreen from 'components/loading_screen';
|
||||
import ConfirmModal from 'components/confirm_modal';
|
||||
import AbstractCommand from '../abstract_command.jsx';
|
||||
import AbstractCommand from '../abstract_command';
|
||||
|
||||
const HEADER = {id: t('integrations.edit'), defaultMessage: 'Edit'};
|
||||
const FOOTER = {id: t('edit_command.update'), defaultMessage: 'Update'};
|
||||
|
||||
Ссылка в новой задаче
Block a user