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