mirror of
https://github.com/mattermost/mattermost.git
synced 2025-02-25 18:55:24 -06:00
MM-47091 : Migrate "components/integrations/abstract_outgoing_webhook.jsx" and tests to TypeScript (#23977)
This commit is contained in:
parent
e377d985cd
commit
949a7875cd
@ -6,7 +6,7 @@ exports[`components/integrations/AbstractOutgoingWebhook should match snapshot 1
|
|||||||
>
|
>
|
||||||
<BackstageHeader>
|
<BackstageHeader>
|
||||||
<Link
|
<Link
|
||||||
to="/test/integrations/outgoing_webhooks"
|
to="/team_name/integrations/outgoing_webhooks"
|
||||||
>
|
>
|
||||||
<MemoizedFormattedMessage
|
<MemoizedFormattedMessage
|
||||||
defaultMessage="Outgoing Webhooks"
|
defaultMessage="Outgoing Webhooks"
|
||||||
@ -14,8 +14,8 @@ exports[`components/integrations/AbstractOutgoingWebhook should match snapshot 1
|
|||||||
/>
|
/>
|
||||||
</Link>
|
</Link>
|
||||||
<MemoizedFormattedMessage
|
<MemoizedFormattedMessage
|
||||||
defaultMessage="add"
|
defaultMessage="Header"
|
||||||
id="add"
|
id="header_id"
|
||||||
/>
|
/>
|
||||||
</BackstageHeader>
|
</BackstageHeader>
|
||||||
<div
|
<div
|
||||||
@ -43,10 +43,10 @@ exports[`components/integrations/AbstractOutgoingWebhook 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=""
|
value="testOutgoingWebhook"
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
className="form__help"
|
className="form__help"
|
||||||
@ -76,10 +76,10 @@ exports[`components/integrations/AbstractOutgoingWebhook should match snapshot 1
|
|||||||
<input
|
<input
|
||||||
className="form-control"
|
className="form-control"
|
||||||
id="description"
|
id="description"
|
||||||
maxLength="500"
|
maxLength={500}
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
type="text"
|
type="text"
|
||||||
value=""
|
value="testing"
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
className="form__help"
|
className="form__help"
|
||||||
@ -109,7 +109,7 @@ exports[`components/integrations/AbstractOutgoingWebhook should match snapshot 1
|
|||||||
<select
|
<select
|
||||||
className="form-control"
|
className="form-control"
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
value="application/x-www-form-urlencoded"
|
value="test_content_type"
|
||||||
>
|
>
|
||||||
<option
|
<option
|
||||||
value="application/x-www-form-urlencoded"
|
value="application/x-www-form-urlencoded"
|
||||||
@ -164,10 +164,11 @@ exports[`components/integrations/AbstractOutgoingWebhook should match snapshot 1
|
|||||||
className="col-md-5 col-sm-8"
|
className="col-md-5 col-sm-8"
|
||||||
>
|
>
|
||||||
<Connect(ChannelSelect)
|
<Connect(ChannelSelect)
|
||||||
id="channelId"
|
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
|
selectDm={false}
|
||||||
selectOpen={true}
|
selectOpen={true}
|
||||||
value=""
|
selectPrivate={false}
|
||||||
|
value="88cxd9wpzpbpfp8pad78xj75pr"
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
className="form__help"
|
className="form__help"
|
||||||
@ -197,10 +198,13 @@ exports[`components/integrations/AbstractOutgoingWebhook should match snapshot 1
|
|||||||
<textarea
|
<textarea
|
||||||
className="form-control"
|
className="form-control"
|
||||||
id="triggerWords"
|
id="triggerWords"
|
||||||
maxLength="1000"
|
maxLength={1000}
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
rows="3"
|
rows={3}
|
||||||
value=""
|
value="test
|
||||||
|
trigger
|
||||||
|
word
|
||||||
|
"
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
className="form__help"
|
className="form__help"
|
||||||
@ -229,6 +233,7 @@ exports[`components/integrations/AbstractOutgoingWebhook should match snapshot 1
|
|||||||
>
|
>
|
||||||
<select
|
<select
|
||||||
className="form-control"
|
className="form-control"
|
||||||
|
id="triggerWhen"
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
value={0}
|
value={0}
|
||||||
>
|
>
|
||||||
@ -271,10 +276,12 @@ exports[`components/integrations/AbstractOutgoingWebhook should match snapshot 1
|
|||||||
<textarea
|
<textarea
|
||||||
className="form-control"
|
className="form-control"
|
||||||
id="callbackUrls"
|
id="callbackUrls"
|
||||||
maxLength="1000"
|
maxLength={1000}
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
rows="3"
|
rows={3}
|
||||||
value=""
|
value="callbackUrl1.com
|
||||||
|
callbackUrl2.com
|
||||||
|
"
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
className="form__help"
|
className="form__help"
|
||||||
@ -314,7 +321,7 @@ exports[`components/integrations/AbstractOutgoingWebhook should match snapshot 1
|
|||||||
/>
|
/>
|
||||||
<Link
|
<Link
|
||||||
className="btn btn-link btn-sm"
|
className="btn btn-link btn-sm"
|
||||||
to="/test/integrations/outgoing_webhooks"
|
to="/team_name/integrations/outgoing_webhooks"
|
||||||
>
|
>
|
||||||
<MemoizedFormattedMessage
|
<MemoizedFormattedMessage
|
||||||
defaultMessage="Cancel"
|
defaultMessage="Cancel"
|
||||||
@ -326,12 +333,12 @@ exports[`components/integrations/AbstractOutgoingWebhook should match snapshot 1
|
|||||||
id="saveWebhook"
|
id="saveWebhook"
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
spinning={false}
|
spinning={false}
|
||||||
spinningText="loading"
|
spinningText="Loading"
|
||||||
type="submit"
|
type="submit"
|
||||||
>
|
>
|
||||||
<MemoizedFormattedMessage
|
<MemoizedFormattedMessage
|
||||||
defaultMessage="save"
|
defaultMessage="Footer"
|
||||||
id="save"
|
id="footer_id"
|
||||||
/>
|
/>
|
||||||
</SpinnerButton>
|
</SpinnerButton>
|
||||||
</div>
|
</div>
|
@ -9,6 +9,8 @@ import ChannelSelect from 'components/channel_select';
|
|||||||
import AbstractIncomingWebhook from 'components/integrations/abstract_incoming_webhook';
|
import AbstractIncomingWebhook from 'components/integrations/abstract_incoming_webhook';
|
||||||
import {Team} from '@mattermost/types/teams';
|
import {Team} from '@mattermost/types/teams';
|
||||||
|
|
||||||
|
type AbstractIncomingWebhookProps = React.ComponentProps<typeof AbstractIncomingWebhook>;
|
||||||
|
|
||||||
describe('components/integrations/AbstractIncomingWebhook', () => {
|
describe('components/integrations/AbstractIncomingWebhook', () => {
|
||||||
const team: Team = {id: 'team_id',
|
const team: Team = {id: 'team_id',
|
||||||
create_at: 0,
|
create_at: 0,
|
||||||
@ -55,7 +57,7 @@ describe('components/integrations/AbstractIncomingWebhook', () => {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const requiredProps = {
|
const requiredProps: AbstractIncomingWebhookProps = {
|
||||||
team,
|
team,
|
||||||
header,
|
header,
|
||||||
footer,
|
footer,
|
||||||
@ -80,10 +82,9 @@ describe('components/integrations/AbstractIncomingWebhook', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should match snapshot, displays client error when no initial hook', () => {
|
test('should match snapshot, displays client error when no initial hook', () => {
|
||||||
const newInitialHook = {};
|
const props = {...requiredProps};
|
||||||
const props = {...requiredProps, initialHook: newInitialHook};
|
delete props.initialHook;
|
||||||
const wrapper = shallow(<AbstractIncomingWebhook {...props}/>);
|
const wrapper = shallow(<AbstractIncomingWebhook {...props}/>);
|
||||||
|
|
||||||
wrapper.find('.btn-primary').simulate('click', {preventDefault() {
|
wrapper.find('.btn-primary').simulate('click', {preventDefault() {
|
||||||
return jest.fn();
|
return jest.fn();
|
||||||
}});
|
}});
|
||||||
|
@ -55,7 +55,7 @@ interface Props {
|
|||||||
/**
|
/**
|
||||||
* The hook used to set the initial state
|
* The hook used to set the initial state
|
||||||
*/
|
*/
|
||||||
initialHook?: IncomingWebhook | Record<string, never>;
|
initialHook?: IncomingWebhook;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether to allow configuration of the default post username.
|
* Whether to allow configuration of the default post username.
|
||||||
@ -77,10 +77,10 @@ export default class AbstractIncomingWebhook extends PureComponent<Props, State>
|
|||||||
constructor(props: Props | Readonly<Props>) {
|
constructor(props: Props | Readonly<Props>) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = this.getStateFromHook(this.props.initialHook || {});
|
this.state = this.getStateFromHook(this.props.initialHook);
|
||||||
}
|
}
|
||||||
|
|
||||||
getStateFromHook = (hook: IncomingWebhook | Record<string, never>) => {
|
getStateFromHook = (hook?: IncomingWebhook) => {
|
||||||
return {
|
return {
|
||||||
displayName: hook?.display_name || '',
|
displayName: hook?.display_name || '',
|
||||||
description: hook?.description || '',
|
description: hook?.description || '',
|
||||||
|
@ -1,42 +0,0 @@
|
|||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
||||||
// See LICENSE.txt for license information.
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import {shallow} from 'enzyme';
|
|
||||||
|
|
||||||
import AbstractOutgoingWebhook from 'components/integrations/abstract_outgoing_webhook';
|
|
||||||
|
|
||||||
describe('components/integrations/AbstractOutgoingWebhook', () => {
|
|
||||||
const emptyFunction = jest.fn();
|
|
||||||
const props = {
|
|
||||||
team: {
|
|
||||||
id: 'test-team-id',
|
|
||||||
name: 'test',
|
|
||||||
},
|
|
||||||
action: emptyFunction,
|
|
||||||
enablePostUsernameOverride: false,
|
|
||||||
enablePostIconOverride: false,
|
|
||||||
header: {id: 'add', defaultMessage: 'add'},
|
|
||||||
footer: {id: 'save', defaultMessage: 'save'},
|
|
||||||
loading: {id: 'loading', defaultMessage: 'loading'},
|
|
||||||
renderExtra: '',
|
|
||||||
serverError: '',
|
|
||||||
};
|
|
||||||
|
|
||||||
test('should match snapshot', () => {
|
|
||||||
const wrapper = shallow(<AbstractOutgoingWebhook {...props}/>);
|
|
||||||
expect(wrapper).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should render username in case of enablePostUsernameOverride is true ', () => {
|
|
||||||
const usernameTrueProps = {...props, enablePostUsernameOverride: true};
|
|
||||||
const wrapper = shallow(<AbstractOutgoingWebhook {...usernameTrueProps}/>);
|
|
||||||
expect(wrapper.find('#username')).toHaveLength(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should render username in case of enablePostUsernameOverride is true ', () => {
|
|
||||||
const iconUrlTrueProps = {...props, enablePostIconOverride: true};
|
|
||||||
const wrapper = shallow(<AbstractOutgoingWebhook {...iconUrlTrueProps}/>);
|
|
||||||
expect(wrapper.find('#iconURL')).toHaveLength(1);
|
|
||||||
});
|
|
||||||
});
|
|
@ -0,0 +1,165 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import {shallow} from 'enzyme';
|
||||||
|
|
||||||
|
import AbstractOutgoingWebhook from 'components/integrations/abstract_outgoing_webhook';
|
||||||
|
import ChannelSelect from 'components/channel_select';
|
||||||
|
import {Team} from '@mattermost/types/teams';
|
||||||
|
|
||||||
|
describe('components/integrations/AbstractOutgoingWebhook', () => {
|
||||||
|
const team: Team = {
|
||||||
|
id: 'team_id',
|
||||||
|
create_at: 0,
|
||||||
|
update_at: 0,
|
||||||
|
delete_at: 0,
|
||||||
|
display_name: 'team_name',
|
||||||
|
name: 'team_name',
|
||||||
|
description: 'team_description',
|
||||||
|
email: 'team_email',
|
||||||
|
type: 'I',
|
||||||
|
company_name: 'team_company_name',
|
||||||
|
allowed_domains: 'team_allowed_domains',
|
||||||
|
invite_id: 'team_invite_id',
|
||||||
|
allow_open_invite: false,
|
||||||
|
scheme_id: 'team_scheme_id',
|
||||||
|
group_constrained: false,
|
||||||
|
};
|
||||||
|
const header = {id: 'header_id', defaultMessage: 'Header'};
|
||||||
|
const footer = {id: 'footer_id', defaultMessage: 'Footer'};
|
||||||
|
const loading = {id: 'loading_id', defaultMessage: 'Loading'};
|
||||||
|
|
||||||
|
const initialHook = {
|
||||||
|
display_name: 'testOutgoingWebhook',
|
||||||
|
channel_id: '88cxd9wpzpbpfp8pad78xj75pr',
|
||||||
|
creator_id: 'test_creator_id',
|
||||||
|
description: 'testing',
|
||||||
|
id: 'test_id',
|
||||||
|
team_id: 'test_team_id',
|
||||||
|
token: 'test_token',
|
||||||
|
trigger_words: ['test', 'trigger', 'word'],
|
||||||
|
trigger_when: 0,
|
||||||
|
callback_urls: ['callbackUrl1.com', 'callbackUrl2.com'],
|
||||||
|
content_type: 'test_content_type',
|
||||||
|
create_at: 0,
|
||||||
|
update_at: 0,
|
||||||
|
delete_at: 0,
|
||||||
|
user_id: 'test_user_id',
|
||||||
|
username: '',
|
||||||
|
icon_url: '',
|
||||||
|
channel_locked: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
const action = jest.fn().mockImplementation(
|
||||||
|
() => {
|
||||||
|
return new Promise<void>((resolve) => {
|
||||||
|
process.nextTick(() => resolve());
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const requiredProps = {
|
||||||
|
team,
|
||||||
|
header,
|
||||||
|
footer,
|
||||||
|
loading,
|
||||||
|
initialHook,
|
||||||
|
enablePostUsernameOverride: false,
|
||||||
|
enablePostIconOverride: false,
|
||||||
|
renderExtra: '',
|
||||||
|
serverError: '',
|
||||||
|
action,
|
||||||
|
};
|
||||||
|
|
||||||
|
test('should match snapshot', () => {
|
||||||
|
const wrapper = shallow(<AbstractOutgoingWebhook {...requiredProps}/>);
|
||||||
|
expect(wrapper).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not render username in case of enablePostUsernameOverride is false ', () => {
|
||||||
|
const usernameTrueProps = {...requiredProps};
|
||||||
|
const wrapper = shallow(<AbstractOutgoingWebhook {...usernameTrueProps}/>);
|
||||||
|
expect(wrapper.find('#username')).toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not render post icon override in case of enablePostIconOverride is false ', () => {
|
||||||
|
const iconUrlTrueProps = {...requiredProps};
|
||||||
|
const wrapper = shallow(<AbstractOutgoingWebhook {...iconUrlTrueProps}/>);
|
||||||
|
expect(wrapper.find('#iconURL')).toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should render username in case of enablePostUsernameOverride is true ', () => {
|
||||||
|
const usernameTrueProps = {...requiredProps, enablePostUsernameOverride: true};
|
||||||
|
const wrapper = shallow(<AbstractOutgoingWebhook {...usernameTrueProps}/>);
|
||||||
|
expect(wrapper.find('#username')).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should render post icon override in case of enablePostIconOverride is true ', () => {
|
||||||
|
const iconUrlTrueProps = {...requiredProps, enablePostIconOverride: true};
|
||||||
|
const wrapper = shallow(<AbstractOutgoingWebhook {...iconUrlTrueProps}/>);
|
||||||
|
expect(wrapper.find('#iconURL')).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should update state.channelId when on channel change', () => {
|
||||||
|
const newChannelId = 'new_channel_id';
|
||||||
|
const evt = {
|
||||||
|
preventDefault: jest.fn(),
|
||||||
|
target: {value: newChannelId},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = shallow(<AbstractOutgoingWebhook {...requiredProps}/>);
|
||||||
|
wrapper.find(ChannelSelect).simulate('change', evt);
|
||||||
|
|
||||||
|
expect(wrapper.state('channelId')).toBe(newChannelId);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should update state.description when on description change', () => {
|
||||||
|
const newDescription = 'new_description';
|
||||||
|
const evt = {
|
||||||
|
preventDefault: jest.fn(),
|
||||||
|
target: {value: newDescription},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = shallow(<AbstractOutgoingWebhook {...requiredProps}/>);
|
||||||
|
wrapper.find('#description').simulate('change', evt);
|
||||||
|
|
||||||
|
expect(wrapper.state('description')).toBe(newDescription);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should update state.username on post username change', () => {
|
||||||
|
const usernameTrueProps = {...requiredProps, enablePostUsernameOverride: true};
|
||||||
|
const newUsername = 'new_username';
|
||||||
|
const evt = {
|
||||||
|
preventDefault: jest.fn(),
|
||||||
|
target: {value: newUsername},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = shallow(<AbstractOutgoingWebhook {...usernameTrueProps}/>);
|
||||||
|
wrapper.find('#username').simulate('change', evt);
|
||||||
|
|
||||||
|
expect(wrapper.state('username')).toBe(newUsername);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should update state.triggerWhen on selection change', () => {
|
||||||
|
const wrapper = shallow(<AbstractOutgoingWebhook {...requiredProps}/>);
|
||||||
|
expect(wrapper.state('triggerWhen')).toBe(0);
|
||||||
|
|
||||||
|
const selector = wrapper.find('#triggerWhen');
|
||||||
|
selector.simulate('change', {target: {value: 1}});
|
||||||
|
console.log('selector: ', selector.debug());
|
||||||
|
expect(wrapper.state('triggerWhen')).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should call action function', () => {
|
||||||
|
const wrapper = shallow(<AbstractOutgoingWebhook {...requiredProps}/>);
|
||||||
|
|
||||||
|
wrapper.find('#displayName').simulate('change', {target: {value: 'name'}});
|
||||||
|
wrapper.find('.btn-primary').simulate('click', {preventDefault() {
|
||||||
|
return jest.fn();
|
||||||
|
}});
|
||||||
|
|
||||||
|
expect(action).toBeCalled();
|
||||||
|
expect(action).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
});
|
@ -1,83 +1,97 @@
|
|||||||
// 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 PropTypes from 'prop-types';
|
import React, {ChangeEventHandler, FormEvent, MouseEvent} from 'react';
|
||||||
import React from 'react';
|
import {FormattedMessage, MessageDescriptor} from 'react-intl';
|
||||||
import {FormattedMessage} from 'react-intl';
|
|
||||||
import {Link} from 'react-router-dom';
|
import {Link} from 'react-router-dom';
|
||||||
|
|
||||||
import {localizeMessage} from 'utils/utils';
|
import {localizeMessage} from 'utils/utils';
|
||||||
|
import {Team} from '@mattermost/types/teams';
|
||||||
import BackstageHeader from 'components/backstage/components/backstage_header';
|
import BackstageHeader from 'components/backstage/components/backstage_header';
|
||||||
import ChannelSelect from 'components/channel_select';
|
import ChannelSelect from 'components/channel_select';
|
||||||
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 ExternalLink from 'components/external_link';
|
import ExternalLink from 'components/external_link';
|
||||||
import {DocLinks} from 'utils/constants';
|
import {DocLinks} from 'utils/constants';
|
||||||
|
import {OutgoingWebhook} from '@mattermost/types/integrations';
|
||||||
|
|
||||||
export default class AbstractOutgoingWebhook extends React.PureComponent {
|
interface State {
|
||||||
static propTypes = {
|
callbackUrls: string;
|
||||||
|
channelId: string;
|
||||||
|
clientError: JSX.Element | null;
|
||||||
|
contentType: string;
|
||||||
|
description: string;
|
||||||
|
displayName: string;
|
||||||
|
iconURL: string;
|
||||||
|
saving: boolean;
|
||||||
|
triggerWhen: number;
|
||||||
|
triggerWords: string;
|
||||||
|
username: string;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
interface Props {
|
||||||
* The current team
|
|
||||||
*/
|
|
||||||
team: PropTypes.object.isRequired,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The header text to render, has id and defaultMessage
|
* The current team
|
||||||
*/
|
*/
|
||||||
header: PropTypes.object.isRequired,
|
team: Team;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The footer text to render, has id and defaultMessage
|
* The header text to render, has id and defaultMessage
|
||||||
*/
|
*/
|
||||||
footer: PropTypes.object.isRequired,
|
header: MessageDescriptor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The spinner loading text to render, has id and defaultMessage
|
* The footer text to render, has id and defaultMessage
|
||||||
*/
|
*/
|
||||||
loading: PropTypes.object.isRequired,
|
footer: MessageDescriptor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Any extra component/node to render
|
* The spinner loading text to render, has id and defaultMessage
|
||||||
*/
|
*/
|
||||||
renderExtra: PropTypes.node.isRequired,
|
loading: MessageDescriptor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The server error text after a failed action
|
* Any extra component/node to render
|
||||||
*/
|
*/
|
||||||
serverError: PropTypes.string.isRequired,
|
renderExtra: React.ReactNode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The hook used to set the initial state
|
* The server error text after a failed action
|
||||||
*/
|
*/
|
||||||
initialHook: PropTypes.object,
|
serverError: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The async function to run when the action button is pressed
|
* The hook used to set the initial state
|
||||||
*/
|
*/
|
||||||
action: PropTypes.func.isRequired,
|
initialHook?: OutgoingWebhook;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether to allow configuration of the default post username.
|
* The async function to run when the action button is pressed
|
||||||
*/
|
*/
|
||||||
enablePostUsernameOverride: PropTypes.bool.isRequired,
|
action: (hook: OutgoingWebhook) => Promise<void>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether to allow configuration of the default post icon.
|
* Whether to allow configuration of the default post username.
|
||||||
*/
|
*/
|
||||||
enablePostIconOverride: PropTypes.bool.isRequired,
|
enablePostUsernameOverride: boolean;
|
||||||
};
|
|
||||||
|
|
||||||
constructor(props) {
|
/**
|
||||||
|
* Whether to allow configuration of the default post icon.
|
||||||
|
*/
|
||||||
|
enablePostIconOverride: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class AbstractOutgoingWebhook extends React.PureComponent<Props, State> {
|
||||||
|
constructor(props: Props | Readonly<Props>) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = this.getStateFromHook(this.props.initialHook || {});
|
this.state = this.getStateFromHook(this.props.initialHook);
|
||||||
}
|
}
|
||||||
|
|
||||||
getStateFromHook = (hook) => {
|
getStateFromHook = (hook?: OutgoingWebhook) => {
|
||||||
let triggerWords = '';
|
let triggerWords = '';
|
||||||
if (hook.trigger_words) {
|
if (hook?.trigger_words) {
|
||||||
let i = 0;
|
let i = 0;
|
||||||
for (i = 0; i < hook.trigger_words.length; i++) {
|
for (i = 0; i < hook.trigger_words.length; i++) {
|
||||||
triggerWords += hook.trigger_words[i] + '\n';
|
triggerWords += hook.trigger_words[i] + '\n';
|
||||||
@ -85,7 +99,7 @@ export default class AbstractOutgoingWebhook extends React.PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let callbackUrls = '';
|
let callbackUrls = '';
|
||||||
if (hook.callback_urls) {
|
if (hook?.callback_urls) {
|
||||||
let i = 0;
|
let i = 0;
|
||||||
for (i = 0; i < hook.callback_urls.length; i++) {
|
for (i = 0; i < hook.callback_urls.length; i++) {
|
||||||
callbackUrls += hook.callback_urls[i] + '\n';
|
callbackUrls += hook.callback_urls[i] + '\n';
|
||||||
@ -93,21 +107,21 @@ export default class AbstractOutgoingWebhook extends React.PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
displayName: hook.display_name || '',
|
displayName: hook?.display_name || '',
|
||||||
description: hook.description || '',
|
description: hook?.description || '',
|
||||||
contentType: hook.content_type || 'application/x-www-form-urlencoded',
|
contentType: hook?.content_type || 'application/x-www-form-urlencoded',
|
||||||
channelId: hook.channel_id || '',
|
channelId: hook?.channel_id || '',
|
||||||
triggerWords,
|
triggerWords,
|
||||||
triggerWhen: hook.trigger_when || 0,
|
triggerWhen: hook?.trigger_when || 0,
|
||||||
callbackUrls,
|
callbackUrls,
|
||||||
saving: false,
|
saving: false,
|
||||||
clientError: null,
|
clientError: null,
|
||||||
username: hook.username || '',
|
username: hook?.username || '',
|
||||||
iconURL: hook.icon_url || '',
|
iconURL: hook?.icon_url || '',
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
handleSubmit = (e) => {
|
handleSubmit = (e: MouseEvent<HTMLElement> | FormEvent<HTMLFormElement>) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
if (this.state.saving) {
|
if (this.state.saving) {
|
||||||
@ -116,7 +130,7 @@ export default class AbstractOutgoingWebhook extends React.PureComponent {
|
|||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
saving: true,
|
saving: true,
|
||||||
clientError: '',
|
clientError: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
const triggerWords = [];
|
const triggerWords = [];
|
||||||
@ -171,67 +185,73 @@ export default class AbstractOutgoingWebhook extends React.PureComponent {
|
|||||||
team_id: this.props.team.id,
|
team_id: this.props.team.id,
|
||||||
channel_id: this.state.channelId,
|
channel_id: this.state.channelId,
|
||||||
trigger_words: triggerWords,
|
trigger_words: triggerWords,
|
||||||
trigger_when: parseInt(this.state.triggerWhen, 10),
|
trigger_when: this.state.triggerWhen,
|
||||||
callback_urls: callbackUrls,
|
callback_urls: callbackUrls,
|
||||||
display_name: this.state.displayName,
|
display_name: this.state.displayName,
|
||||||
content_type: this.state.contentType,
|
content_type: this.state.contentType,
|
||||||
description: this.state.description,
|
description: this.state.description,
|
||||||
username: this.state.username,
|
username: this.state.username,
|
||||||
icon_url: this.state.iconURL,
|
icon_url: this.state.iconURL,
|
||||||
|
id: this.props.initialHook?.id || '',
|
||||||
|
create_at: this.props.initialHook?.create_at || 0,
|
||||||
|
update_at: this.props.initialHook?.update_at || 0,
|
||||||
|
delete_at: this.props.initialHook?.delete_at || 0,
|
||||||
|
creator_id: this.props.initialHook?.creator_id || '',
|
||||||
|
token: this.props.initialHook?.token || '',
|
||||||
};
|
};
|
||||||
|
|
||||||
this.props.action(hook).then(() => this.setState({saving: false}));
|
this.props.action(hook).then(() => this.setState({saving: false}));
|
||||||
};
|
};
|
||||||
|
|
||||||
updateDisplayName = (e) => {
|
updateDisplayName: ChangeEventHandler<HTMLInputElement> = (e) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
displayName: e.target.value,
|
displayName: e.target.value,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
updateDescription = (e) => {
|
updateDescription: ChangeEventHandler<HTMLInputElement> = (e) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
description: e.target.value,
|
description: e.target.value,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
updateContentType = (e) => {
|
updateContentType: ChangeEventHandler<HTMLSelectElement> = (e) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
contentType: e.target.value,
|
contentType: e.target.value,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
updateChannelId = (e) => {
|
updateChannelId: ChangeEventHandler<HTMLSelectElement> = (e) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
channelId: e.target.value,
|
channelId: e.target.value,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
updateTriggerWords = (e) => {
|
updateTriggerWords: ChangeEventHandler<HTMLTextAreaElement> = (e) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
triggerWords: e.target.value,
|
triggerWords: e.target.value,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
updateTriggerWhen = (e) => {
|
updateTriggerWhen: ChangeEventHandler<HTMLSelectElement> = (e) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
triggerWhen: e.target.value,
|
triggerWhen: parseInt(e.target.value, 10),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
updateCallbackUrls = (e) => {
|
updateCallbackUrls: ChangeEventHandler<HTMLTextAreaElement> = (e) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
callbackUrls: e.target.value,
|
callbackUrls: e.target.value,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
updateUsername = (e) => {
|
updateUsername: ChangeEventHandler<HTMLInputElement> = (e) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
username: e.target.value,
|
username: e.target.value,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
updateIconURL = (e) => {
|
updateIconURL: ChangeEventHandler<HTMLInputElement> = (e) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
iconURL: e.target.value,
|
iconURL: e.target.value,
|
||||||
});
|
});
|
||||||
@ -241,9 +261,9 @@ export default class AbstractOutgoingWebhook extends React.PureComponent {
|
|||||||
const contentTypeOption1 = 'application/x-www-form-urlencoded';
|
const contentTypeOption1 = 'application/x-www-form-urlencoded';
|
||||||
const contentTypeOption2 = 'application/json';
|
const contentTypeOption2 = 'application/json';
|
||||||
|
|
||||||
var headerToRender = this.props.header;
|
const headerToRender = this.props.header;
|
||||||
var footerToRender = this.props.footer;
|
const footerToRender = this.props.footer;
|
||||||
var renderExtra = this.props.renderExtra;
|
const renderExtra = this.props.renderExtra;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='backstage-content'>
|
<div className='backstage-content'>
|
||||||
@ -278,7 +298,7 @@ export default class AbstractOutgoingWebhook 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}
|
||||||
@ -305,7 +325,7 @@ export default class AbstractOutgoingWebhook extends React.PureComponent {
|
|||||||
<input
|
<input
|
||||||
id='description'
|
id='description'
|
||||||
type='text'
|
type='text'
|
||||||
maxLength='500'
|
maxLength={500}
|
||||||
className='form-control'
|
className='form-control'
|
||||||
value={this.state.description}
|
value={this.state.description}
|
||||||
onChange={this.updateDescription}
|
onChange={this.updateDescription}
|
||||||
@ -377,10 +397,11 @@ export default class AbstractOutgoingWebhook extends React.PureComponent {
|
|||||||
</label>
|
</label>
|
||||||
<div className='col-md-5 col-sm-8'>
|
<div className='col-md-5 col-sm-8'>
|
||||||
<ChannelSelect
|
<ChannelSelect
|
||||||
id='channelId'
|
|
||||||
value={this.state.channelId}
|
value={this.state.channelId}
|
||||||
onChange={this.updateChannelId}
|
onChange={this.updateChannelId}
|
||||||
selectOpen={true}
|
selectOpen={true}
|
||||||
|
selectPrivate={false}
|
||||||
|
selectDm={false}
|
||||||
/>
|
/>
|
||||||
<div className='form__help'>
|
<div className='form__help'>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
@ -403,8 +424,8 @@ export default class AbstractOutgoingWebhook extends React.PureComponent {
|
|||||||
<div className='col-md-5 col-sm-8'>
|
<div className='col-md-5 col-sm-8'>
|
||||||
<textarea
|
<textarea
|
||||||
id='triggerWords'
|
id='triggerWords'
|
||||||
rows='3'
|
rows={3}
|
||||||
maxLength='1000'
|
maxLength={1000}
|
||||||
className='form-control'
|
className='form-control'
|
||||||
value={this.state.triggerWords}
|
value={this.state.triggerWords}
|
||||||
onChange={this.updateTriggerWords}
|
onChange={this.updateTriggerWords}
|
||||||
@ -429,6 +450,7 @@ export default class AbstractOutgoingWebhook extends React.PureComponent {
|
|||||||
</label>
|
</label>
|
||||||
<div className='col-md-5 col-sm-8'>
|
<div className='col-md-5 col-sm-8'>
|
||||||
<select
|
<select
|
||||||
|
id='triggerWhen'
|
||||||
className='form-control'
|
className='form-control'
|
||||||
value={this.state.triggerWhen}
|
value={this.state.triggerWhen}
|
||||||
onChange={this.updateTriggerWhen}
|
onChange={this.updateTriggerWhen}
|
||||||
@ -465,8 +487,8 @@ export default class AbstractOutgoingWebhook extends React.PureComponent {
|
|||||||
<div className='col-md-5 col-sm-8'>
|
<div className='col-md-5 col-sm-8'>
|
||||||
<textarea
|
<textarea
|
||||||
id='callbackUrls'
|
id='callbackUrls'
|
||||||
rows='3'
|
rows={3}
|
||||||
maxLength='1000'
|
maxLength={1000}
|
||||||
className='form-control'
|
className='form-control'
|
||||||
value={this.state.callbackUrls}
|
value={this.state.callbackUrls}
|
||||||
onChange={this.updateCallbackUrls}
|
onChange={this.updateCallbackUrls}
|
||||||
@ -507,7 +529,7 @@ export default class AbstractOutgoingWebhook extends React.PureComponent {
|
|||||||
<input
|
<input
|
||||||
id='username'
|
id='username'
|
||||||
type='text'
|
type='text'
|
||||||
maxLength='22'
|
maxLength={22}
|
||||||
className='form-control'
|
className='form-control'
|
||||||
value={this.state.username}
|
value={this.state.username}
|
||||||
onChange={this.updateUsername}
|
onChange={this.updateUsername}
|
||||||
@ -536,7 +558,7 @@ export default class AbstractOutgoingWebhook extends React.PureComponent {
|
|||||||
<input
|
<input
|
||||||
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}
|
||||||
@ -568,7 +590,7 @@ export default class AbstractOutgoingWebhook extends React.PureComponent {
|
|||||||
className='btn btn-primary'
|
className='btn btn-primary'
|
||||||
type='submit'
|
type='submit'
|
||||||
spinning={this.state.saving}
|
spinning={this.state.saving}
|
||||||
spinningText={localizeMessage(this.props.loading.id, this.props.loading.defaultMessage)}
|
spinningText={localizeMessage(this.props.loading.id as string, this.props.loading.defaultMessage as string)}
|
||||||
onClick={this.handleSubmit}
|
onClick={this.handleSubmit}
|
||||||
id='saveWebhook'
|
id='saveWebhook'
|
||||||
>
|
>
|
@ -6,7 +6,7 @@ import {useHistory} from 'react-router-dom';
|
|||||||
|
|
||||||
import {t} from 'utils/i18n';
|
import {t} from 'utils/i18n';
|
||||||
|
|
||||||
import AbstractOutgoingWebhook from 'components/integrations/abstract_outgoing_webhook.jsx';
|
import AbstractOutgoingWebhook from 'components/integrations/abstract_outgoing_webhook';
|
||||||
|
|
||||||
import {Team} from '@mattermost/types/teams';
|
import {Team} from '@mattermost/types/teams';
|
||||||
import {OutgoingWebhook} from '@mattermost/types/integrations';
|
import {OutgoingWebhook} from '@mattermost/types/integrations';
|
||||||
|
@ -10,7 +10,7 @@ import {ServerError} from '@mattermost/types/errors';
|
|||||||
|
|
||||||
import {getHistory} from 'utils/browser_history';
|
import {getHistory} from 'utils/browser_history';
|
||||||
import ConfirmModal from 'components/confirm_modal';
|
import ConfirmModal from 'components/confirm_modal';
|
||||||
import AbstractOutgoingWebhook from 'components/integrations/abstract_outgoing_webhook.jsx';
|
import AbstractOutgoingWebhook from 'components/integrations/abstract_outgoing_webhook';
|
||||||
import LoadingScreen from 'components/loading_screen';
|
import LoadingScreen from 'components/loading_screen';
|
||||||
|
|
||||||
const HEADER = {id: 'integrations.edit', defaultMessage: 'Edit'};
|
const HEADER = {id: 'integrations.edit', defaultMessage: 'Edit'};
|
||||||
|
Loading…
Reference in New Issue
Block a user