summaryrefslogtreecommitdiffstats
path: root/webapp/components/integrations/components
diff options
context:
space:
mode:
Diffstat (limited to 'webapp/components/integrations/components')
-rw-r--r--webapp/components/integrations/components/abstract_incoming_webhook.jsx253
-rw-r--r--webapp/components/integrations/components/abstract_outgoing_webhook.jsx483
-rw-r--r--webapp/components/integrations/components/add_command/add_command.jsx615
-rw-r--r--webapp/components/integrations/components/add_command/index.js25
-rw-r--r--webapp/components/integrations/components/add_incoming_webhook/add_incoming_webhook.jsx68
-rw-r--r--webapp/components/integrations/components/add_incoming_webhook/index.js25
-rw-r--r--webapp/components/integrations/components/add_oauth_app/add_oauth_app.jsx441
-rw-r--r--webapp/components/integrations/components/add_oauth_app/index.js25
-rw-r--r--webapp/components/integrations/components/add_outgoing_webhook/add_outgoing_webhook.jsx69
-rw-r--r--webapp/components/integrations/components/add_outgoing_webhook/index.js25
-rw-r--r--webapp/components/integrations/components/commands_container/commands_container.jsx78
-rw-r--r--webapp/components/integrations/components/commands_container/index.js29
-rw-r--r--webapp/components/integrations/components/confirm_integration/confirm_integration.jsx258
-rw-r--r--webapp/components/integrations/components/confirm_integration/index.js16
-rw-r--r--webapp/components/integrations/components/delete_integration.jsx51
-rw-r--r--webapp/components/integrations/components/edit_command/edit_command.jsx727
-rw-r--r--webapp/components/integrations/components/edit_command/index.js31
-rw-r--r--webapp/components/integrations/components/edit_incoming_webhook/edit_incoming_webhook.jsx112
-rw-r--r--webapp/components/integrations/components/edit_incoming_webhook/index.js30
-rw-r--r--webapp/components/integrations/components/edit_outgoing_webhook/edit_outgoing_webhook.jsx169
-rw-r--r--webapp/components/integrations/components/edit_outgoing_webhook/index.js30
-rw-r--r--webapp/components/integrations/components/installed_command.jsx176
-rw-r--r--webapp/components/integrations/components/installed_commands/index.js25
-rw-r--r--webapp/components/integrations/components/installed_commands/installed_commands.jsx160
-rw-r--r--webapp/components/integrations/components/installed_incoming_webhook.jsx147
-rw-r--r--webapp/components/integrations/components/installed_incoming_webhooks.jsx178
-rw-r--r--webapp/components/integrations/components/installed_oauth_app.jsx270
-rw-r--r--webapp/components/integrations/components/installed_oauth_apps/index.js31
-rw-r--r--webapp/components/integrations/components/installed_oauth_apps/installed_oauth_apps.jsx165
-rw-r--r--webapp/components/integrations/components/installed_outgoing_webhook.jsx244
-rw-r--r--webapp/components/integrations/components/installed_outgoing_webhooks.jsx182
-rw-r--r--webapp/components/integrations/components/integration_option.jsx41
-rw-r--r--webapp/components/integrations/components/integrations.jsx175
33 files changed, 0 insertions, 5354 deletions
diff --git a/webapp/components/integrations/components/abstract_incoming_webhook.jsx b/webapp/components/integrations/components/abstract_incoming_webhook.jsx
deleted file mode 100644
index 1253842a7..000000000
--- a/webapp/components/integrations/components/abstract_incoming_webhook.jsx
+++ /dev/null
@@ -1,253 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-import PropTypes from 'prop-types';
-
-import BackstageHeader from 'components/backstage/components/backstage_header.jsx';
-import ChannelSelect from 'components/channel_select.jsx';
-import {FormattedMessage} from 'react-intl';
-import FormError from 'components/form_error.jsx';
-import SpinnerButton from 'components/spinner_button.jsx';
-import {Link} from 'react-router/es6';
-
-export default class AbstractIncomingWebhook extends React.Component {
- static propTypes = {
-
- /**
- * The current team
- */
- team: PropTypes.object.isRequired,
-
- /**
- * The header text to render, has id and defaultMessage
- */
- header: PropTypes.object.isRequired,
-
- /**
- * The footer text to render, has id and defaultMessage
- */
- footer: PropTypes.object.isRequired,
-
- /**
- * The server error text after a failed action
- */
- serverError: PropTypes.string.isRequired,
-
- /**
- * The hook used to set the initial state
- */
- initialHook: PropTypes.object,
-
- /**
- * The async function to run when the action button is pressed
- */
- action: PropTypes.func.isRequired
- }
-
- constructor(props) {
- super(props);
-
- this.state = this.getStateFromHook(this.props.initialHook || {});
- }
-
- getStateFromHook = (hook) => {
- return {
- displayName: hook.display_name || '',
- description: hook.description || '',
- channelId: hook.channel_id || '',
- saving: false,
- serverError: '',
- clientError: null
- };
- }
-
- handleSubmit = (e) => {
- e.preventDefault();
-
- if (this.state.saving) {
- return;
- }
-
- this.setState({
- saving: true,
- serverError: '',
- clientError: ''
- });
-
- if (!this.state.channelId) {
- this.setState({
- saving: false,
- clientError: (
- <FormattedMessage
- id='add_incoming_webhook.channelRequired'
- defaultMessage='A valid channel is required'
- />
- )
- });
-
- return;
- }
-
- const hook = {
- channel_id: this.state.channelId,
- display_name: this.state.displayName,
- description: this.state.description
- };
-
- this.props.action(hook).then(() => this.setState({saving: false}));
- }
-
- updateDisplayName = (e) => {
- this.setState({
- displayName: e.target.value
- });
- }
-
- updateDescription = (e) => {
- this.setState({
- description: e.target.value
- });
- }
-
- updateChannelId = (e) => {
- this.setState({
- channelId: e.target.value
- });
- }
-
- render() {
- var headerToRender = this.props.header;
- var footerToRender = this.props.footer;
-
- return (
- <div className='backstage-content'>
- <BackstageHeader>
- <Link to={`/${this.props.team.name}/integrations/incoming_webhooks`}>
- <FormattedMessage
- id='installed_incoming_webhooks.header'
- defaultMessage='Incoming Webhooks'
- />
- </Link>
- <FormattedMessage
- id={headerToRender.id}
- defaultMessage={headerToRender.defaultMessage}
- />
- </BackstageHeader>
- <div className='backstage-form'>
- <form
- className='form-horizontal'
- onSubmit={this.handleSubmit}
- >
- <div className='form-group'>
- <label
- className='control-label col-sm-4'
- htmlFor='displayName'
- >
- <FormattedMessage
- id='add_incoming_webhook.displayName'
- defaultMessage='Display Name'
- />
- </label>
- <div className='col-md-5 col-sm-8'>
- <input
- id='displayName'
- type='text'
- maxLength='64'
- className='form-control'
- value={this.state.displayName}
- onChange={this.updateDisplayName}
- />
- <div className='form__help'>
- <FormattedMessage
- id='add_incoming_webhook.displayName.help'
- defaultMessage='Display name for your incoming webhook made of up to 64 characters.'
- />
- </div>
- </div>
- </div>
- <div className='form-group'>
- <label
- className='control-label col-sm-4'
- htmlFor='description'
- >
- <FormattedMessage
- id='add_incoming_webhook.description'
- defaultMessage='Description'
- />
- </label>
- <div className='col-md-5 col-sm-8'>
- <input
- id='description'
- type='text'
- maxLength='128'
- className='form-control'
- value={this.state.description}
- onChange={this.updateDescription}
- />
- <div className='form__help'>
- <FormattedMessage
- id='add_incoming_webhook.description.help'
- defaultMessage='Description for your incoming webhook.'
- />
- </div>
- </div>
- </div>
- <div className='form-group'>
- <label
- className='control-label col-sm-4'
- htmlFor='channelId'
- >
- <FormattedMessage
- id='add_incoming_webhook.channel'
- defaultMessage='Channel'
- />
- </label>
- <div className='col-md-5 col-sm-8'>
- <ChannelSelect
- id='channelId'
- value={this.state.channelId}
- onChange={this.updateChannelId}
- selectOpen={true}
- selectPrivate={true}
- />
- <div className='form__help'>
- <FormattedMessage
- id='add_incoming_webhook.channel.help'
- defaultMessage='Public or private channel that receives the webhook payloads. You must belong to the private channel when setting up the webhook.'
- />
- </div>
- </div>
- </div>
- <div className='backstage-form__footer'>
- <FormError
- type='backstage'
- errors={[this.props.serverError, this.state.clientError]}
- />
- <Link
- className='btn btn-sm'
- to={`/${this.props.team.name}/integrations/incoming_webhooks`}
- >
- <FormattedMessage
- id='add_incoming_webhook.cancel'
- defaultMessage='Cancel'
- />
- </Link>
- <SpinnerButton
- className='btn btn-primary'
- type='submit'
- spinning={this.state.saving}
- onClick={this.handleSubmit}
- >
- <FormattedMessage
- id={footerToRender.id}
- defaultMessage={footerToRender.defaultMessage}
- />
- </SpinnerButton>
- </div>
- </form>
- </div>
- </div>
- );
- }
-}
diff --git a/webapp/components/integrations/components/abstract_outgoing_webhook.jsx b/webapp/components/integrations/components/abstract_outgoing_webhook.jsx
deleted file mode 100644
index 397423395..000000000
--- a/webapp/components/integrations/components/abstract_outgoing_webhook.jsx
+++ /dev/null
@@ -1,483 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-import PropTypes from 'prop-types';
-
-import TeamStore from 'stores/team_store.jsx';
-
-import {localizeMessage} from 'utils/utils.jsx';
-
-import BackstageHeader from 'components/backstage/components/backstage_header.jsx';
-import ChannelSelect from 'components/channel_select.jsx';
-import {FormattedMessage} from 'react-intl';
-import FormError from 'components/form_error.jsx';
-import {Link} from 'react-router/es6';
-import SpinnerButton from 'components/spinner_button.jsx';
-
-export default class AbstractOutgoingWebhook extends React.Component {
- static propTypes = {
-
- /**
- * The current team
- */
- team: PropTypes.object.isRequired,
-
- /**
- * The header text to render, has id and defaultMessage
- */
- header: PropTypes.object.isRequired,
-
- /**
- * The footer text to render, has id and defaultMessage
- */
- footer: PropTypes.object.isRequired,
-
- /**
- * Any extra component/node to render
- */
- renderExtra: PropTypes.node.isRequired,
-
- /**
- * The server error text after a failed action
- */
- serverError: PropTypes.string.isRequired,
-
- /**
- * The hook used to set the initial state
- */
- initialHook: PropTypes.object,
-
- /**
- * The async function to run when the action button is pressed
- */
- action: PropTypes.func.isRequired
- }
-
- constructor(props) {
- super(props);
-
- this.state = this.getStateFromHook(this.props.initialHook || {});
- }
-
- getStateFromHook = (hook) => {
- let triggerWords = '';
- if (hook.trigger_words) {
- let i = 0;
- for (i = 0; i < hook.trigger_words.length; i++) {
- triggerWords += hook.trigger_words[i] + '\n';
- }
- }
-
- let callbackUrls = '';
- if (hook.callback_urls) {
- let i = 0;
- for (i = 0; i < hook.callback_urls.length; i++) {
- callbackUrls += hook.callback_urls[i] + '\n';
- }
- }
-
- return {
- displayName: hook.display_name || '',
- description: hook.description || '',
- contentType: hook.content_type || 'application/x-www-form-urlencoded',
- channelId: hook.channel_id || '',
- triggerWords,
- triggerWhen: hook.trigger_when || 0,
- callbackUrls,
- saving: false,
- clientError: null
- };
- }
-
- handleSubmit = (e) => {
- e.preventDefault();
-
- if (this.state.saving) {
- return;
- }
-
- this.setState({
- saving: true,
- clientError: ''
- });
-
- const triggerWords = [];
- if (this.state.triggerWords) {
- for (let triggerWord of this.state.triggerWords.split('\n')) {
- triggerWord = triggerWord.trim();
-
- if (triggerWord.length > 0) {
- triggerWords.push(triggerWord);
- }
- }
- }
-
- if (!this.state.channelId && triggerWords.length === 0) {
- this.setState({
- saving: false,
- clientError: (
- <FormattedMessage
- id='add_outgoing_webhook.triggerWordsOrChannelRequired'
- defaultMessage='A valid channel or a list of trigger words is required'
- />
- )
- });
-
- return;
- }
-
- const callbackUrls = [];
- for (let callbackUrl of this.state.callbackUrls.split('\n')) {
- callbackUrl = callbackUrl.trim();
-
- if (callbackUrl.length > 0) {
- callbackUrls.push(callbackUrl);
- }
- }
-
- if (callbackUrls.length === 0) {
- this.setState({
- saving: false,
- clientError: (
- <FormattedMessage
- id='add_outgoing_webhook.callbackUrlsRequired'
- defaultMessage='One or more callback URLs are required'
- />
- )
- });
-
- return;
- }
-
- const hook = {
- team_id: TeamStore.getCurrentId(),
- channel_id: this.state.channelId,
- trigger_words: triggerWords,
- trigger_when: parseInt(this.state.triggerWhen, 10),
- callback_urls: callbackUrls,
- display_name: this.state.displayName,
- content_type: this.state.contentType,
- description: this.state.description
- };
-
- this.props.action(hook).then(() => this.setState({saving: false}));
- }
-
- updateDisplayName = (e) => {
- this.setState({
- displayName: e.target.value
- });
- }
-
- updateDescription = (e) => {
- this.setState({
- description: e.target.value
- });
- }
-
- updateContentType = (e) => {
- this.setState({
- contentType: e.target.value
- });
- }
-
- updateChannelId = (e) => {
- this.setState({
- channelId: e.target.value
- });
- }
-
- updateTriggerWords = (e) => {
- this.setState({
- triggerWords: e.target.value
- });
- }
-
- updateTriggerWhen = (e) => {
- this.setState({
- triggerWhen: e.target.value
- });
- }
-
- updateCallbackUrls = (e) => {
- this.setState({
- callbackUrls: e.target.value
- });
- }
-
- render() {
- const contentTypeOption1 = 'application/x-www-form-urlencoded';
- const contentTypeOption2 = 'application/json';
-
- var headerToRender = this.props.header;
- var footerToRender = this.props.footer;
- var renderExtra = this.props.renderExtra;
-
- return (
- <div className='backstage-content'>
- <BackstageHeader>
- <Link to={`/${this.props.team.name}/integrations/outgoing_webhooks`}>
- <FormattedMessage
- id='installed_outgoing_webhooks.header'
- defaultMessage='Outgoing Webhooks'
- />
- </Link>
- <FormattedMessage
- id={headerToRender.id}
- defaultMessage={headerToRender.defaultMessage}
- />
- </BackstageHeader>
- <div className='backstage-form'>
- <form
- className='form-horizontal'
- onSubmit={this.handleSubmit}
- >
- <div className='form-group'>
- <label
- className='control-label col-sm-4'
- htmlFor='displayName'
- >
- <FormattedMessage
- id='add_outgoing_webhook.displayName'
- defaultMessage='Display Name'
- />
- </label>
- <div className='col-md-5 col-sm-8'>
- <input
- id='displayName'
- type='text'
- maxLength='64'
- className='form-control'
- value={this.state.displayName}
- onChange={this.updateDisplayName}
- />
- <div className='form__help'>
- <FormattedMessage
- id='add_outgoing_webhook.displayName.help'
- defaultMessage='Display name for your incoming webhook made of up to 64 characters.'
- />
- </div>
- </div>
- </div>
- <div className='form-group'>
- <label
- className='control-label col-sm-4'
- htmlFor='description'
- >
- <FormattedMessage
- id='add_outgoing_webhook.description'
- defaultMessage='Description'
- />
- </label>
- <div className='col-md-5 col-sm-8'>
- <input
- id='description'
- type='text'
- maxLength='128'
- className='form-control'
- value={this.state.description}
- onChange={this.updateDescription}
- />
- <div className='form__help'>
- <FormattedMessage
- id='add_outgoing_webhook.description.help'
- defaultMessage='Description for your incoming webhook.'
- />
- </div>
- </div>
- </div>
- <div className='form-group'>
- <label
- className='control-label col-sm-4'
- htmlFor='contentType'
- >
- <FormattedMessage
- id='add_outgoing_webhook.content_Type'
- defaultMessage='Content Type'
- />
- </label>
- <div className='col-md-5 col-sm-8'>
- <select
- className='form-control'
- value={this.state.contentType}
- onChange={this.updateContentType}
- >
- <option
- value={contentTypeOption1}
- >
- {contentTypeOption1}
- </option>
- <option
- value={contentTypeOption2}
- >
- {contentTypeOption2}
- </option>
- </select>
- <div className='form__help'>
- <FormattedMessage
- id='add_outgoing_webhook.contentType.help1'
- defaultMessage='Choose the content type by which the response will be sent.'
- />
- </div>
- <div className='form__help'>
- <FormattedMessage
- id='add_outgoing_webhook.contentType.help2'
- defaultMessage='If application/x-www-form-urlencoded is chosen, the server assumes you will be encoding the parameters in a URL format.'
- />
- </div>
- <div className='form__help'>
- <FormattedMessage
- id='add_outgoing_webhook.contentType.help3'
- defaultMessage='If application/json is chosen, the server assumes you will posting JSON data.'
- />
- </div>
- </div>
- </div>
- <div className='form-group'>
- <label
- className='control-label col-sm-4'
- htmlFor='channelId'
- >
- <FormattedMessage
- id='add_outgoing_webhook.channel'
- defaultMessage='Channel'
- />
- </label>
- <div className='col-md-5 col-sm-8'>
- <ChannelSelect
- id='channelId'
- value={this.state.channelId}
- onChange={this.updateChannelId}
- selectOpen={true}
- />
- <div className='form__help'>
- <FormattedMessage
- id='add_outgoing_webhook.channel.help'
- defaultMessage='Public channel to receive webhook payloads. Optional if at least one Trigger Word is specified.'
- />
- </div>
- </div>
- </div>
- <div className='form-group'>
- <label
- className='control-label col-sm-4'
- htmlFor='triggerWords'
- >
- <FormattedMessage
- id='add_outgoing_webhook.triggerWords'
- defaultMessage='Trigger Words (One Per Line)'
- />
- </label>
- <div className='col-md-5 col-sm-8'>
- <textarea
- id='triggerWords'
- rows='3'
- maxLength='1000'
- className='form-control'
- value={this.state.triggerWords}
- onChange={this.updateTriggerWords}
- />
- <div className='form__help'>
- <FormattedMessage
- id='add_outgoing_webhook.triggerWords.help'
- defaultMessage='Messages that start with one of the specified words will trigger the outgoing webhook. Optional if Channel is selected.'
- />
- </div>
- </div>
- </div>
- <div className='form-group'>
- <label
- className='control-label col-sm-4'
- htmlFor='triggerWords'
- >
- <FormattedMessage
- id='add_outgoing_webhook.triggerWordsTriggerWhen'
- defaultMessage='Trigger When'
- />
- </label>
- <div className='col-md-5 col-sm-8'>
- <select
- className='form-control'
- value={this.state.triggerWhen}
- onChange={this.updateTriggerWhen}
- >
- <option
- value='0'
- >
- {localizeMessage('add_outgoing_webhook.triggerWordsTriggerWhenFullWord', 'First word matches a trigger word exactly')}
- </option>
- <option
- value='1'
- >
- {localizeMessage('add_outgoing_webhook.triggerWordsTriggerWhenStartsWith', 'First word starts with a trigger word')}
- </option>
- </select>
- <div className='form__help'>
- <FormattedMessage
- id='add_outgoing_webhook.triggerWordsTriggerWhen.help'
- defaultMessage='Choose when to trigger the outgoing webhook; if the first word of a message matches a Trigger Word exactly, or if it starts with a Trigger Word.'
- />
- </div>
- </div>
- </div>
- <div className='form-group'>
- <label
- className='control-label col-sm-4'
- htmlFor='callbackUrls'
- >
- <FormattedMessage
- id='add_outgoing_webhook.callbackUrls'
- defaultMessage='Callback URLs (One Per Line)'
- />
- </label>
- <div className='col-md-5 col-sm-8'>
- <textarea
- id='callbackUrls'
- rows='3'
- maxLength='1000'
- className='form-control'
- value={this.state.callbackUrls}
- onChange={this.updateCallbackUrls}
- />
- <div className='form__help'>
- <FormattedMessage
- id='add_outgoing_webhook.callbackUrls.help'
- defaultMessage='The URL that messages will be sent to.'
- />
- </div>
- </div>
- </div>
- <div className='backstage-form__footer'>
- <FormError
- type='backstage'
- errors={[this.props.serverError, this.state.clientError]}
- />
- <Link
- className='btn btn-sm'
- to={`/${this.props.team.name}/integrations/outgoing_webhooks`}
- >
- <FormattedMessage
- id='add_outgoing_webhook.cancel'
- defaultMessage='Cancel'
- />
- </Link>
- <SpinnerButton
- className='btn btn-primary'
- type='submit'
- spinning={this.state.saving}
- onClick={this.handleSubmit}
- >
- <FormattedMessage
- id={footerToRender.id}
- defaultMessage={footerToRender.defaultMessage}
- />
- </SpinnerButton>
- {renderExtra}
- </div>
- </form>
- </div>
- </div>
- );
- }
-}
diff --git a/webapp/components/integrations/components/add_command/add_command.jsx b/webapp/components/integrations/components/add_command/add_command.jsx
deleted file mode 100644
index 28f6115f9..000000000
--- a/webapp/components/integrations/components/add_command/add_command.jsx
+++ /dev/null
@@ -1,615 +0,0 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-import PropTypes from 'prop-types';
-
-import * as Utils from 'utils/utils.jsx';
-
-import BackstageHeader from 'components/backstage/components/backstage_header.jsx';
-import {FormattedMessage} from 'react-intl';
-import FormError from 'components/form_error.jsx';
-import {browserHistory, Link} from 'react-router/es6';
-import SpinnerButton from 'components/spinner_button.jsx';
-import Constants from 'utils/constants.jsx';
-
-const REQUEST_POST = 'P';
-const REQUEST_GET = 'G';
-
-export default class AddCommand extends React.PureComponent {
- static propTypes = {
-
- /**
- * The team data
- */
- team: PropTypes.object,
-
- /**
- * The request state for addCommand action. Contains status and error
- */
- addCommandRequest: PropTypes.object.isRequired,
-
- actions: PropTypes.shape({
-
- /**
- * The function to call to add new command
- */
- addCommand: PropTypes.func.isRequired
- }).isRequired
- }
-
- constructor(props) {
- super(props);
-
- this.state = {
- displayName: '',
- description: '',
- trigger: '',
- url: '',
- method: REQUEST_POST,
- username: '',
- iconUrl: '',
- autocomplete: false,
- autocompleteHint: '',
- autocompleteDescription: '',
- saving: false,
- serverError: '',
- clientError: null
- };
- }
-
- handleSubmit = (e) => {
- e.preventDefault();
-
- if (this.state.saving) {
- return;
- }
-
- this.setState({
- saving: true,
- serverError: '',
- clientError: ''
- });
-
- let triggerWord = this.state.trigger.trim().toLowerCase();
- if (triggerWord.indexOf('/') === 0) {
- triggerWord = triggerWord.substr(1);
- }
-
- const command = {
- display_name: this.state.displayName,
- description: this.state.description,
- trigger: triggerWord,
- url: this.state.url.trim(),
- method: this.state.method,
- username: this.state.username,
- icon_url: this.state.iconUrl,
- auto_complete: this.state.autocomplete,
- team_id: this.props.team.id
- };
-
- if (command.auto_complete) {
- command.auto_complete_desc = this.state.autocompleteDescription;
- command.auto_complete_hint = this.state.autocompleteHint;
- }
-
- if (!command.trigger) {
- this.setState({
- saving: false,
- clientError: (
- <FormattedMessage
- id='add_command.triggerRequired'
- defaultMessage='A trigger word is required'
- />
- )
- });
-
- return;
- }
-
- if (command.trigger.indexOf('/') === 0) {
- this.setState({
- saving: false,
- clientError: (
- <FormattedMessage
- id='add_command.triggerInvalidSlash'
- defaultMessage='A trigger word cannot begin with a /'
- />
- )
- });
-
- return;
- }
-
- if (command.trigger.indexOf(' ') !== -1) {
- this.setState({
- saving: false,
- clientError: (
- <FormattedMessage
- id='add_command.triggerInvalidSpace'
- defaultMessage='A trigger word must not contain spaces'
- />
- )
- });
- return;
- }
-
- if (command.trigger.length < Constants.MIN_TRIGGER_LENGTH ||
- command.trigger.length > Constants.MAX_TRIGGER_LENGTH) {
- this.setState({
- saving: false,
- clientError: (
- <FormattedMessage
- id='add_command.triggerInvalidLength'
- defaultMessage='A trigger word must contain between {min} and {max} characters'
- values={{
- min: Constants.MIN_TRIGGER_LENGTH,
- max: Constants.MAX_TRIGGER_LENGTH
- }}
- />
- )
- });
-
- return;
- }
-
- if (!command.url) {
- this.setState({
- saving: false,
- clientError: (
- <FormattedMessage
- id='add_command.urlRequired'
- defaultMessage='A request URL is required'
- />
- )
- });
-
- return;
- }
-
- this.props.actions.addCommand(command).then(
- (data) => {
- if (data) {
- browserHistory.push(`/${this.props.team.name}/integrations/commands/confirm?type=commands&id=${data.id}`);
- } else {
- this.setState({
- saving: false,
- serverError: this.props.addCommandRequest.error.message
- });
- }
- }
- );
- }
-
- updateDisplayName = (e) => {
- this.setState({
- displayName: e.target.value
- });
- }
-
- updateDescription = (e) => {
- this.setState({
- description: e.target.value
- });
- }
-
- updateTrigger = (e) => {
- this.setState({
- trigger: e.target.value
- });
- }
-
- updateUrl = (e) => {
- this.setState({
- url: e.target.value
- });
- }
-
- updateMethod = (e) => {
- this.setState({
- method: e.target.value
- });
- }
-
- updateUsername = (e) => {
- this.setState({
- username: e.target.value
- });
- }
-
- updateIconUrl = (e) => {
- this.setState({
- iconUrl: e.target.value
- });
- }
-
- updateAutocomplete = (e) => {
- this.setState({
- autocomplete: e.target.checked
- });
- }
-
- updateAutocompleteHint = (e) => {
- this.setState({
- autocompleteHint: e.target.value
- });
- }
-
- updateAutocompleteDescription = (e) => {
- this.setState({
- autocompleteDescription: e.target.value
- });
- }
-
- render() {
- let autocompleteFields = null;
- if (this.state.autocomplete) {
- autocompleteFields = [(
- <div
- key='autocompleteHint'
- className='form-group'
- >
- <label
- className='control-label col-sm-4'
- htmlFor='autocompleteHint'
- >
- <FormattedMessage
- id='add_command.autocompleteHint'
- defaultMessage='Autocomplete Hint'
- />
- </label>
- <div className='col-md-5 col-sm-8'>
- <input
- id='autocompleteHint'
- type='text'
- maxLength='1024'
- className='form-control'
- value={this.state.autocompleteHint}
- onChange={this.updateAutocompleteHint}
- placeholder={Utils.localizeMessage('add_command.autocompleteHint.placeholder', 'Example: [Patient Name]')}
- />
- <div className='form__help'>
- <FormattedMessage
- id='add_command.autocompleteHint.help'
- defaultMessage='(Optional) Arguments associated with your slash command, displayed as help in the autocomplete list.'
- />
- </div>
- </div>
- </div>
- ),
- (
- <div
- key='autocompleteDescription'
- className='form-group'
- >
- <label
- className='control-label col-sm-4'
- htmlFor='autocompleteDescription'
- >
- <FormattedMessage
- id='add_command.autocompleteDescription'
- defaultMessage='Autocomplete Description'
- />
- </label>
- <div className='col-md-5 col-sm-8'>
- <input
- id='description'
- type='text'
- maxLength='128'
- className='form-control'
- value={this.state.autocompleteDescription}
- onChange={this.updateAutocompleteDescription}
- placeholder={Utils.localizeMessage('add_command.autocompleteDescription.placeholder', 'Example: "Returns search results for patient records"')}
- />
- <div className='form__help'>
- <FormattedMessage
- id='add_command.autocompleteDescription.help'
- defaultMessage='(Optional) Short description of slash command for the autocomplete list.'
- />
- </div>
- </div>
- </div>
- )];
- }
-
- return (
- <div className='backstage-content row'>
- <BackstageHeader>
- <Link to={'/' + this.props.team.name + '/integrations/commands'}>
- <FormattedMessage
- id='installed_command.header'
- defaultMessage='Slash Commands'
- />
- </Link>
- <FormattedMessage
- id='integrations.add'
- defaultMessage='Add'
- />
- </BackstageHeader>
- <div className='backstage-form'>
- <form
- className='form-horizontal'
- onSubmit={this.handleSubmit}
- >
- <div className='form-group'>
- <label
- className='control-label col-sm-4'
- htmlFor='displayName'
- >
- <FormattedMessage
- id='add_command.displayName'
- defaultMessage='Display Name'
- />
- </label>
- <div className='col-md-5 col-sm-8'>
- <input
- id='displayName'
- type='text'
- maxLength='64'
- className='form-control'
- value={this.state.displayName}
- onChange={this.updateDisplayName}
- />
- <div className='form__help'>
- <FormattedMessage
- id='add_command.displayName.help'
- defaultMessage='Display name for your slash command made of up to 64 characters.'
- />
- </div>
- </div>
- </div>
- <div className='form-group'>
- <label
- className='control-label col-sm-4'
- htmlFor='description'
- >
- <FormattedMessage
- id='add_command.description'
- defaultMessage='Description'
- />
- </label>
- <div className='col-md-5 col-sm-8'>
- <input
- id='description'
- type='text'
- maxLength='128'
- className='form-control'
- value={this.state.description}
- onChange={this.updateDescription}
- />
- <div className='form__help'>
- <FormattedMessage
- id='add_command.description.help'
- defaultMessage='Description for your incoming webhook.'
- />
- </div>
- </div>
- </div>
- <div className='form-group'>
- <label
- className='control-label col-sm-4'
- htmlFor='trigger'
- >
- <FormattedMessage
- id='add_command.trigger'
- defaultMessage='Command Trigger Word'
- />
- </label>
- <div className='col-md-5 col-sm-8'>
- <input
- id='trigger'
- type='text'
- maxLength={Constants.MAX_TRIGGER_LENGTH}
- className='form-control'
- value={this.state.trigger}
- onChange={this.updateTrigger}
- placeholder={Utils.localizeMessage('add_command.trigger.placeholder', 'Command trigger e.g. "hello" not including the slash')}
- />
- <div className='form__help'>
- <FormattedMessage
- id='add_command.trigger.help'
- defaultMessage='Trigger word must be unique, and cannot begin with a slash or contain any spaces.'
- />
- </div>
- <div className='form__help'>
- <FormattedMessage
- id='add_command.trigger.helpExamples'
- defaultMessage='Examples: client, employee, patient, weather'
- />
- </div>
- <div className='form__help'>
- <FormattedMessage
- id='add_command.trigger.helpReserved'
- defaultMessage='Reserved: {link}'
- values={{
- link: (
- <a
- href='https://docs.mattermost.com/help/messaging/executing-commands.html#built-in-commands'
- target='_blank'
- rel='noopener noreferrer'
- >
- <FormattedMessage
- id='add_command.trigger.helpReservedLinkText'
- defaultMessage='see list of built-in slash commands'
- />
- </a>
- )
- }}
- />
- </div>
- </div>
- </div>
- <div className='form-group'>
- <label
- className='control-label col-sm-4'
- htmlFor='url'
- >
- <FormattedMessage
- id='add_command.url'
- defaultMessage='Request URL'
- />
- </label>
- <div className='col-md-5 col-sm-8'>
- <input
- id='url'
- type='text'
- maxLength='1024'
- className='form-control'
- value={this.state.url}
- onChange={this.updateUrl}
- placeholder={Utils.localizeMessage('add_command.url.placeholder', 'Must start with http:// or https://')}
- />
- <div className='form__help'>
- <FormattedMessage
- id='add_command.url.help'
- defaultMessage='The callback URL to receive the HTTP POST or GET event request when the slash command is run.'
- />
- </div>
- </div>
- </div>
- <div className='form-group'>
- <label
- className='control-label col-sm-4'
- htmlFor='method'
- >
- <FormattedMessage
- id='add_command.method'
- defaultMessage='Request Method'
- />
- </label>
- <div className='col-md-5 col-sm-8'>
- <select
- id='method'
- className='form-control'
- value={this.state.method}
- onChange={this.updateMethod}
- >
- <option value={REQUEST_POST}>
- {Utils.localizeMessage('add_command.method.post', 'POST')}
- </option>
- <option value={REQUEST_GET}>
- {Utils.localizeMessage('add_command.method.get', 'GET')}
- </option>
- </select>
- <div className='form__help'>
- <FormattedMessage
- id='add_command.method.help'
- defaultMessage='The type of command request issued to the Request URL.'
- />
- </div>
- </div>
- </div>
- <div className='form-group'>
- <label
- className='control-label col-sm-4'
- htmlFor='username'
- >
- <FormattedMessage
- id='add_command.username'
- defaultMessage='Response Username'
- />
- </label>
- <div className='col-md-5 col-sm-8'>
- <input
- id='username'
- type='text'
- maxLength='64'
- className='form-control'
- value={this.state.username}
- onChange={this.updateUsername}
- placeholder={Utils.localizeMessage('add_command.username.placeholder', 'Username')}
- />
- <div className='form__help'>
- <FormattedMessage
- id='add_command.username.help'
- defaultMessage='(Optional) Choose a username override for responses for this slash command. Usernames can consist of up to 22 characters consisting of lowercase letters, numbers and they symbols "-", "_", and "." .'
- />
- </div>
- </div>
- </div>
- <div className='form-group'>
- <label
- className='control-label col-sm-4'
- htmlFor='iconUrl'
- >
- <FormattedMessage
- id='add_command.iconUrl'
- defaultMessage='Response Icon'
- />
- </label>
- <div className='col-md-5 col-sm-8'>
- <input
- id='iconUrl'
- type='text'
- maxLength='1024'
- className='form-control'
- value={this.state.iconUrl}
- onChange={this.updateIconUrl}
- placeholder={Utils.localizeMessage('add_command.iconUrl.placeholder', 'https://www.example.com/myicon.png')}
- />
- <div className='form__help'>
- <FormattedMessage
- id='add_command.iconUrl.help'
- defaultMessage='(Optional) Choose a profile picture override for the post responses to this slash command. Enter the URL of a .png or .jpg file at least 128 pixels by 128 pixels.'
- />
- </div>
- </div>
- </div>
- <div className='form-group'>
- <label
- className='control-label col-sm-4'
- htmlFor='autocomplete'
- >
- <FormattedMessage
- id='add_command.autocomplete'
- defaultMessage='Autocomplete'
- />
- </label>
- <div className='col-md-5 col-sm-8 checkbox'>
- <input
- id='autocomplete'
- type='checkbox'
- checked={this.state.autocomplete}
- onChange={this.updateAutocomplete}
- />
- <div className='form__help'>
- <FormattedMessage
- id='add_command.autocomplete.help'
- defaultMessage='(Optional) Show slash command in autocomplete list.'
- />
- </div>
- </div>
- </div>
- {autocompleteFields}
- <div className='backstage-form__footer'>
- <FormError
- type='backstage'
- errors={[this.state.serverError, this.state.clientError]}
- />
- <Link
- className='btn btn-sm'
- to={'/' + this.props.team.name + '/integrations/commands'}
- >
- <FormattedMessage
- id='add_command.cancel'
- defaultMessage='Cancel'
- />
- </Link>
- <SpinnerButton
- className='btn btn-primary'
- type='submit'
- spinning={this.state.saving}
- onClick={this.handleSubmit}
- >
- <FormattedMessage
- id='add_command.save'
- defaultMessage='Save'
- />
- </SpinnerButton>
- </div>
- </form>
- </div>
- </div>
- );
- }
-}
diff --git a/webapp/components/integrations/components/add_command/index.js b/webapp/components/integrations/components/add_command/index.js
deleted file mode 100644
index 9ac7db220..000000000
--- a/webapp/components/integrations/components/add_command/index.js
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import {connect} from 'react-redux';
-import {bindActionCreators} from 'redux';
-import {addCommand} from 'mattermost-redux/actions/integrations';
-
-import AddCommand from './add_command.jsx';
-
-function mapStateToProps(state, ownProps) {
- return {
- ...ownProps,
- addCommandRequest: state.requests.integrations.addCommand
- };
-}
-
-function mapDispatchToProps(dispatch) {
- return {
- actions: bindActionCreators({
- addCommand
- }, dispatch)
- };
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(AddCommand);
diff --git a/webapp/components/integrations/components/add_incoming_webhook/add_incoming_webhook.jsx b/webapp/components/integrations/components/add_incoming_webhook/add_incoming_webhook.jsx
deleted file mode 100644
index 23f0fad6f..000000000
--- a/webapp/components/integrations/components/add_incoming_webhook/add_incoming_webhook.jsx
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-import {browserHistory} from 'react-router/es6';
-import PropTypes from 'prop-types';
-
-import AbstractIncomingWebhook from 'components/integrations/components/abstract_incoming_webhook.jsx';
-
-const HEADER = {id: 'integrations.add', defaultMessage: 'Add'};
-const FOOTER = {id: 'add_incoming_webhook.save', defaultMessage: 'Save'};
-
-export default class AddIncomingWebhook extends React.PureComponent {
- static propTypes = {
-
- /**
- * The current team
- */
- team: PropTypes.object.isRequired,
-
- /**
- * The request state for createIncomingHook action. Contains status and error
- */
- createIncomingHookRequest: PropTypes.object.isRequired,
-
- actions: PropTypes.shape({
-
- /**
- * The function to call to add a new incoming webhook
- */
- createIncomingHook: PropTypes.func.isRequired
- }).isRequired
- }
-
- constructor(props) {
- super(props);
-
- this.state = {
- serverError: ''
- };
- }
-
- addIncomingHook = async (hook) => {
- this.setState({serverError: ''});
-
- const data = await this.props.actions.createIncomingHook(hook);
- if (data) {
- browserHistory.push(`/${this.props.team.name}/integrations/confirm?type=incoming_webhooks&id=${data.id}`);
- return;
- }
-
- if (this.props.createIncomingHookRequest.error) {
- this.setState({serverError: this.props.createIncomingHookRequest.error.message});
- }
- }
-
- render() {
- return (
- <AbstractIncomingWebhook
- team={this.props.team}
- header={HEADER}
- footer={FOOTER}
- action={this.addIncomingHook}
- serverError={this.state.serverError}
- />
- );
- }
-}
diff --git a/webapp/components/integrations/components/add_incoming_webhook/index.js b/webapp/components/integrations/components/add_incoming_webhook/index.js
deleted file mode 100644
index ed2b53ba8..000000000
--- a/webapp/components/integrations/components/add_incoming_webhook/index.js
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
- import {connect} from 'react-redux';
- import {bindActionCreators} from 'redux';
- import {createIncomingHook} from 'mattermost-redux/actions/integrations';
-
- import AddIncomingWebhook from './add_incoming_webhook.jsx';
-
- function mapStateToProps(state, ownProps) {
- return {
- ...ownProps,
- createIncomingHookRequest: state.requests.integrations.createIncomingHook
- };
- }
-
- function mapDispatchToProps(dispatch) {
- return {
- actions: bindActionCreators({
- createIncomingHook
- }, dispatch)
- };
- }
-
- export default connect(mapStateToProps, mapDispatchToProps)(AddIncomingWebhook); \ No newline at end of file
diff --git a/webapp/components/integrations/components/add_oauth_app/add_oauth_app.jsx b/webapp/components/integrations/components/add_oauth_app/add_oauth_app.jsx
deleted file mode 100644
index cad3244e3..000000000
--- a/webapp/components/integrations/components/add_oauth_app/add_oauth_app.jsx
+++ /dev/null
@@ -1,441 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-import PropTypes from 'prop-types';
-
-import BackstageHeader from 'components/backstage/components/backstage_header.jsx';
-import {FormattedMessage} from 'react-intl';
-import FormError from 'components/form_error.jsx';
-import {browserHistory, Link} from 'react-router/es6';
-import SpinnerButton from 'components/spinner_button.jsx';
-
-export default class AddOAuthApp extends React.PureComponent {
- static propTypes = {
-
- /**
- * The team data
- */
- team: PropTypes.object,
-
- /**
- * The request state for addOAuthApp action. Contains status and error
- */
- addOAuthAppRequest: PropTypes.object.isRequired,
-
- actions: PropTypes.shape({
-
- /**
- * The function to call to add new OAuthApp
- */
- addOAuthApp: PropTypes.func.isRequired
- }).isRequired
- }
-
- constructor(props) {
- super(props);
-
- this.image = new Image();
- this.image.onload = this.imageLoaded;
-
- this.state = {
- name: '',
- description: '',
- homepage: '',
- icon_url: '',
- callbackUrls: '',
- is_trusted: false,
- has_icon: false,
- saving: false,
- serverError: '',
- clientError: null
- };
- }
-
- imageLoaded = () => {
- this.setState({
- has_icon: true,
- icon_url: this.refs.icon_url.value
- });
- }
-
- handleSubmit = (e) => {
- e.preventDefault();
-
- if (this.state.saving) {
- return;
- }
-
- this.setState({
- saving: true,
- serverError: '',
- clientError: ''
- });
-
- if (!this.state.name) {
- this.setState({
- saving: false,
- clientError: (
- <FormattedMessage
- id='add_oauth_app.nameRequired'
- defaultMessage='Name for the OAuth 2.0 application is required.'
- />
- )
- });
-
- return;
- }
-
- if (!this.state.description) {
- this.setState({
- saving: false,
- clientError: (
- <FormattedMessage
- id='add_oauth_app.descriptionRequired'
- defaultMessage='Description for the OAuth 2.0 application is required.'
- />
- )
- });
-
- return;
- }
-
- if (!this.state.homepage) {
- this.setState({
- saving: false,
- clientError: (
- <FormattedMessage
- id='add_oauth_app.homepageRequired'
- defaultMessage='Homepage for the OAuth 2.0 application is required.'
- />
- )
- });
-
- return;
- }
-
- const callbackUrls = [];
- for (let callbackUrl of this.state.callbackUrls.split('\n')) {
- callbackUrl = callbackUrl.trim();
-
- if (callbackUrl.length > 0) {
- callbackUrls.push(callbackUrl);
- }
- }
-
- if (callbackUrls.length === 0) {
- this.setState({
- saving: false,
- clientError: (
- <FormattedMessage
- id='add_oauth_app.callbackUrlsRequired'
- defaultMessage='One or more callback URLs are required.'
- />
- )
- });
-
- return;
- }
-
- const app = {
- name: this.state.name,
- callback_urls: callbackUrls,
- homepage: this.state.homepage,
- description: this.state.description,
- is_trusted: this.state.is_trusted,
- icon_url: this.state.icon_url
- };
-
- this.props.actions.addOAuthApp(app).then(
- (data) => {
- const {error} = this.props.addOAuthAppRequest;
- if (error) {
- this.setState({
- saving: false,
- serverError: error.message
- });
- } else {
- browserHistory.
- push(`/${this.props.team.name}/integrations/confirm?type=oauth2-apps&id=${data.id}`);
- }
- }
- );
- }
-
- updateName = (e) => {
- this.setState({
- name: e.target.value
- });
- }
-
- updateTrusted = (e) => {
- this.setState({
- is_trusted: e.target.value === 'true'
- });
- }
-
- updateDescription = (e) => {
- this.setState({
- description: e.target.value
- });
- }
-
- updateHomepage = (e) => {
- this.setState({
- homepage: e.target.value
- });
- }
-
- updateIconUrl = (e) => {
- this.setState({
- has_icon: false,
- icon_url: ''
- });
- this.image.src = e.target.value;
- }
-
- updateCallbackUrls = (e) => {
- this.setState({
- callbackUrls: e.target.value
- });
- }
-
- render() {
- let icon;
- if (this.state.has_icon) {
- icon = (
- <div className='integration__icon'>
- <img src={this.state.icon_url}/>
- </div>
- );
- }
-
- return (
- <div className='backstage-content'>
- <BackstageHeader>
- <Link to={`/${this.props.team.name}/integrations/oauth2-apps`}>
- <FormattedMessage
- id='installed_oauth_apps.header'
- defaultMessage='Installed OAuth2 Apps'
- />
- </Link>
- <FormattedMessage
- id='add_oauth_app.header'
- defaultMessage='Add'
- />
- </BackstageHeader>
- <div className='backstage-form'>
- {icon}
- <form className='form-horizontal'>
- <div className='form-group'>
- <label
- className='control-label col-sm-4'
- htmlFor='is_trusted'
- >
- <FormattedMessage
- id='installed_oauth_apps.trusted'
- defaultMessage='Is Trusted'
- />
- </label>
- <div className='col-md-5 col-sm-8'>
- <label className='radio-inline'>
- <input
- type='radio'
- value='true'
- name='is_trusted'
- checked={this.state.is_trusted}
- onChange={this.updateTrusted}
- />
- <FormattedMessage
- id='installed_oauth_apps.trusted.yes'
- defaultMessage='Yes'
- />
- </label>
- <label className='radio-inline'>
- <input
- type='radio'
- value='false'
- name='is_trusted'
- checked={!this.state.is_trusted}
- onChange={this.updateTrusted}
- />
- <FormattedMessage
- id='installed_oauth_apps.trusted.no'
- defaultMessage='No'
- />
- </label>
- <div className='form__help'>
- <FormattedMessage
- id='add_oauth_app.trusted.help'
- defaultMessage="When true, the OAuth 2.0 application is considered trusted by the Mattermost server and doesn't require the user to accept authorization. When false, an additional window will appear, asking the user to accept or deny the authorization."
- />
- </div>
- </div>
- </div>
- <div className='form-group'>
- <label
- className='control-label col-sm-4'
- htmlFor='name'
- >
- <FormattedMessage
- id='installed_oauth_apps.name'
- defaultMessage='Display Name'
- />
- </label>
- <div className='col-md-5 col-sm-8'>
- <input
- id='name'
- type='text'
- maxLength='64'
- className='form-control'
- value={this.state.name}
- onChange={this.updateName}
- />
- <div className='form__help'>
- <FormattedMessage
- id='add_oauth_app.name.help'
- defaultMessage='Display name for your OAuth 2.0 application made of up to 64 characters.'
- />
- </div>
- </div>
- </div>
- <div className='form-group'>
- <label
- className='control-label col-sm-4'
- htmlFor='description'
- >
- <FormattedMessage
- id='installed_oauth_apps.description'
- defaultMessage='Description'
- />
- </label>
- <div className='col-md-5 col-sm-8'>
- <input
- id='description'
- type='text'
- maxLength='512'
- className='form-control'
- value={this.state.description}
- onChange={this.updateDescription}
- />
- <div className='form__help'>
- <FormattedMessage
- id='add_oauth_app.description.help'
- defaultMessage='Description for your OAuth 2.0 application.'
- />
- </div>
- </div>
- </div>
- <div className='form-group'>
- <label
- className='control-label col-sm-4'
- htmlFor='homepage'
- >
- <FormattedMessage
- id='installed_oauth_apps.homepage'
- defaultMessage='Homepage'
- />
- </label>
- <div className='col-md-5 col-sm-8'>
- <input
- id='homepage'
- type='url'
- maxLength='256'
- className='form-control'
- value={this.state.homepage}
- onChange={this.updateHomepage}
- />
- <div className='form__help'>
- <FormattedMessage
- id='add_oauth_app.homepage.help'
- defaultMessage='The URL for the homepage of the OAuth 2.0 application. Make sure you use HTTP or HTTPS in your URL depending on your server configuration.'
- />
- </div>
- </div>
- </div>
- <div className='form-group'>
- <label
- className='control-label col-sm-4'
- htmlFor='icon_url'
- >
- <FormattedMessage
- id='installed_oauth_apps.iconUrl'
- defaultMessage='Icon URL'
- />
- </label>
- <div className='col-md-5 col-sm-8'>
- <input
- id='icon_url'
- ref='icon_url'
- type='url'
- maxLength='512'
- className='form-control'
- onChange={this.updateIconUrl}
- />
- <div className='form__help'>
- <FormattedMessage
- id='add_oauth_app.icon.help'
- defaultMessage='The URL for the homepage of the OAuth 2.0 application. Make sure you use HTTP or HTTPS in your URL depending on your server configuration.'
- />
- </div>
- </div>
- </div>
- <div className='form-group'>
- <label
- className='control-label col-sm-4'
- htmlFor='callbackUrls'
- >
- <FormattedMessage
- id='installed_oauth_apps.callbackUrls'
- defaultMessage='Callback URLs (One Per Line)'
- />
- </label>
- <div className='col-md-5 col-sm-8'>
- <textarea
- id='callbackUrls'
- rows='3'
- maxLength='1024'
- className='form-control'
- value={this.state.callbackUrls}
- onChange={this.updateCallbackUrls}
- />
- <div className='form__help'>
- <FormattedMessage
- id='add_oauth_app.callbackUrls.help'
- defaultMessage='The redirect URIs to which the service will redirect users after accepting or denying authorization of your application, and which will handle authorization codes or access tokens. Must be a valid URL and start with http:// or https://.'
- />
- </div>
- </div>
- </div>
- <div className='backstage-form__footer'>
- <FormError
- type='backstage'
- errors={[this.state.serverError, this.state.clientError]}
- />
- <Link
- className='btn btn-sm'
- to={`/${this.props.team.name}/integrations/oauth2-apps`}
- >
- <FormattedMessage
- id='installed_oauth_apps.cancel'
- defaultMessage='Cancel'
- />
- </Link>
- <SpinnerButton
- className='btn btn-primary'
- type='submit'
- spinning={this.state.saving}
- onClick={this.handleSubmit}
- >
- <FormattedMessage
- id='installed_oauth_apps.save'
- defaultMessage='Save'
- />
- </SpinnerButton>
- </div>
- </form>
- </div>
- </div>
- );
- }
-}
diff --git a/webapp/components/integrations/components/add_oauth_app/index.js b/webapp/components/integrations/components/add_oauth_app/index.js
deleted file mode 100644
index be3446c45..000000000
--- a/webapp/components/integrations/components/add_oauth_app/index.js
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import {connect} from 'react-redux';
-import {bindActionCreators} from 'redux';
-import {addOAuthApp} from 'mattermost-redux/actions/integrations';
-
-import AddOAuthApp from './add_oauth_app.jsx';
-
-function mapStateToProps(state, ownProps) {
- return {
- ...ownProps,
- addOAuthAppRequest: state.requests.integrations.addOAuthApp
- };
-}
-
-function mapDispatchToProps(dispatch) {
- return {
- actions: bindActionCreators({
- addOAuthApp
- }, dispatch)
- };
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(AddOAuthApp);
diff --git a/webapp/components/integrations/components/add_outgoing_webhook/add_outgoing_webhook.jsx b/webapp/components/integrations/components/add_outgoing_webhook/add_outgoing_webhook.jsx
deleted file mode 100644
index 41ab8a073..000000000
--- a/webapp/components/integrations/components/add_outgoing_webhook/add_outgoing_webhook.jsx
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import AbstractOutgoingWebhook from 'components/integrations/components/abstract_outgoing_webhook.jsx';
-
-import React from 'react';
-import {browserHistory} from 'react-router/es6';
-import PropTypes from 'prop-types';
-
-const HEADER = {id: 'integrations.add', defaultMessage: 'Add'};
-const FOOTER = {id: 'add_outgoing_webhook.save', defaultMessage: 'Save'};
-
-export default class AddOutgoingWebhook extends React.PureComponent {
- static propTypes = {
-
- /**
- * The current team
- */
- team: PropTypes.object.isRequired,
-
- /**
- * The request state for createOutgoingHook action. Contains status and error
- */
- createOutgoingHookRequest: PropTypes.object.isRequired,
-
- actions: PropTypes.shape({
-
- /**
- * The function to call to add a new outgoing webhook
- */
- createOutgoingHook: PropTypes.func.isRequired
- }).isRequired
- }
-
- constructor(props) {
- super(props);
-
- this.state = {
- serverError: ''
- };
- }
-
- addOutgoingHook = async (hook) => {
- this.setState({serverError: ''});
-
- const data = await this.props.actions.createOutgoingHook(hook);
- if (data) {
- browserHistory.push(`/${this.props.team.name}/integrations/confirm?type=outgoing_webhooks&id=${data.id}`);
- return;
- }
-
- if (this.props.createOutgoingHookRequest.error) {
- this.setState({serverError: this.props.createOutgoingHookRequest.error.message});
- }
- }
-
- render() {
- return (
- <AbstractOutgoingWebhook
- team={this.props.team}
- header={HEADER}
- footer={FOOTER}
- renderExtra={''}
- action={this.addOutgoingHook}
- serverError={this.state.serverError}
- />
- );
- }
-}
diff --git a/webapp/components/integrations/components/add_outgoing_webhook/index.js b/webapp/components/integrations/components/add_outgoing_webhook/index.js
deleted file mode 100644
index f930ac81f..000000000
--- a/webapp/components/integrations/components/add_outgoing_webhook/index.js
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import {connect} from 'react-redux';
-import {bindActionCreators} from 'redux';
-import {createOutgoingHook} from 'mattermost-redux/actions/integrations';
-
-import AddOutgoingWebhook from './add_outgoing_webhook.jsx';
-
-function mapStateToProps(state, ownProps) {
- return {
- ...ownProps,
- createOutgoingHookRequest: state.requests.integrations.createOutgoingHook
- };
-}
-
-function mapDispatchToProps(dispatch) {
- return {
- actions: bindActionCreators({
- createOutgoingHook
- }, dispatch)
- };
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(AddOutgoingWebhook);
diff --git a/webapp/components/integrations/components/commands_container/commands_container.jsx b/webapp/components/integrations/components/commands_container/commands_container.jsx
deleted file mode 100644
index 8f89ff631..000000000
--- a/webapp/components/integrations/components/commands_container/commands_container.jsx
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-import PropTypes from 'prop-types';
-
-export default class CommandsContainer extends React.PureComponent {
- static propTypes = {
-
- /**
- * The team data needed to pass into child components
- */
- team: PropTypes.object,
-
- /**
- * The user data needed to pass into child components
- */
- user: PropTypes.object,
-
- /**
- * The children prop needed to render child component
- */
- children: PropTypes.node.isRequired,
-
- /**
- * Set if user is admin
- */
- isAdmin: PropTypes.bool,
-
- /**
- * The users collection
- */
- users: PropTypes.object,
-
- /**
- * Installed slash commands to display
- */
- commands: PropTypes.array,
-
- actions: PropTypes.shape({
-
- /**
- * The function to call to fetch team commands
- */
- getCustomTeamCommands: PropTypes.func.isRequired
- }).isRequired
- }
-
- constructor(props) {
- super(props);
- this.state = {
- loading: true
- };
- }
-
- componentDidMount() {
- if (window.mm_config.EnableCommands === 'true') {
- this.props.actions.getCustomTeamCommands(this.props.team.id).then(
- () => this.setState({loading: false})
- );
- }
- }
-
- render() {
- return (
- <div>
- {React.cloneElement(this.props.children, {
- loading: this.state.loading,
- commands: this.props.commands || [],
- users: this.props.users,
- team: this.props.team,
- user: this.props.user,
- isAdmin: this.props.isAdmin
- })}
- </div>
- );
- }
-}
diff --git a/webapp/components/integrations/components/commands_container/index.js b/webapp/components/integrations/components/commands_container/index.js
deleted file mode 100644
index ed0a4c138..000000000
--- a/webapp/components/integrations/components/commands_container/index.js
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import {connect} from 'react-redux';
-import {bindActionCreators} from 'redux';
-import {getCustomTeamCommands} from 'mattermost-redux/actions/integrations';
-
-import {getCommands} from 'mattermost-redux/selectors/entities/integrations';
-import {getUsers} from 'mattermost-redux/selectors/entities/users';
-
-import CommandsContainer from './commands_container.jsx';
-
-function mapStateToProps(state, ownProps) {
- return {
- ...ownProps,
- commands: Object.values(getCommands(state)),
- users: getUsers(state)
- };
-}
-
-function mapDispatchToProps(dispatch) {
- return {
- actions: bindActionCreators({
- getCustomTeamCommands
- }, dispatch)
- };
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(CommandsContainer); \ No newline at end of file
diff --git a/webapp/components/integrations/components/confirm_integration/confirm_integration.jsx b/webapp/components/integrations/components/confirm_integration/confirm_integration.jsx
deleted file mode 100644
index 05dd61efb..000000000
--- a/webapp/components/integrations/components/confirm_integration/confirm_integration.jsx
+++ /dev/null
@@ -1,258 +0,0 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-import PropTypes from 'prop-types';
-
-import BackstageHeader from 'components/backstage/components/backstage_header.jsx';
-import {FormattedMessage, FormattedHTMLMessage} from 'react-intl';
-import {Link, browserHistory} from 'react-router/es6';
-
-import UserStore from 'stores/user_store.jsx';
-import IntegrationStore from 'stores/integration_store.jsx';
-
-import Constants from 'utils/constants.jsx';
-
-export default class ConfirmIntegration extends React.Component {
- static get propTypes() {
- return {
- team: PropTypes.object,
- location: PropTypes.object,
- commands: PropTypes.object,
- loading: PropTypes.bool
- };
- }
-
- constructor(props) {
- super(props);
-
- this.handleIntegrationChange = this.handleIntegrationChange.bind(this);
- this.handleKeyPress = this.handleKeyPress.bind(this);
-
- const userId = UserStore.getCurrentId();
-
- this.state = {
- type: this.props.location.query.type,
- id: this.props.location.query.id,
- oauthApps: IntegrationStore.getOAuthApps(userId),
- loading: !IntegrationStore.hasReceivedOAuthApps(userId)
- };
- }
-
- componentDidMount() {
- IntegrationStore.addChangeListener(this.handleIntegrationChange);
- window.addEventListener('keypress', this.handleKeyPress);
- }
-
- componentWillUnmount() {
- IntegrationStore.removeChangeListener(this.handleIntegrationChange);
- window.removeEventListener('keypress', this.handleKeyPress);
- }
-
- handleIntegrationChange() {
- const userId = UserStore.getCurrentId();
-
- this.setState({
- oauthApps: IntegrationStore.getOAuthApps(userId),
- loading: !IntegrationStore.hasReceivedOAuthApps(userId)
- });
- }
-
- handleKeyPress(e) {
- if (e.key === 'Enter') {
- browserHistory.push('/' + this.props.team.name + '/integrations/' + this.state.type);
- }
- }
-
- render() {
- let headerText = null;
- let helpText = null;
- let tokenText = null;
-
- if (this.props.loading === true) {
- return (<div/>);
- }
-
- if (this.state.type === Constants.Integrations.COMMAND) {
- headerText = (
- <FormattedMessage
- id={'installed_commands.header'}
- defaultMessage='Slash Commands'
- />
- );
- helpText = (
- <p>
- <FormattedHTMLMessage
- id='add_command.doneHelp'
- defaultMessage='Your slash command has been set up. The following token will be sent in the outgoing payload. Please use it to verify the request came from your Mattermost team (see <a href="https://docs.mattermost.com/developer/slash-commands.html">documentation</a> for further details).'
- />
- </p>
- );
- tokenText = (
- <p className='word-break--all'>
- <FormattedHTMLMessage
- id='add_command.token'
- defaultMessage='<b>Token</b>: {token}'
- values={{
- token: this.props.commands[this.state.id].token
- }}
- />
- </p>
- );
- } else if (this.state.type === Constants.Integrations.INCOMING_WEBHOOK) {
- headerText = (
- <FormattedMessage
- id={'installed_incoming_webhooks.header'}
- defaultMessage='Incoming Webhooks'
- />
- );
- helpText = (
- <p>
- <FormattedHTMLMessage
- id='add_incoming_webhook.doneHelp'
- defaultMessage='Your incoming webhook has been set up. Please send data to the following URL (see <a href=\"https://docs.mattermost.com/developer/webhooks-incoming.html\">documentation</a> for further details).'
- />
- </p>
- );
- tokenText = (
- <p className='word-break--all'>
- <FormattedHTMLMessage
- id='add_incoming_webhook.url'
- defaultMessage='<b>URL</b>: {url}'
- values={{
- url: window.location.origin + '/hooks/' + this.state.id
- }}
- />
- </p>
- );
- } else if (this.state.type === Constants.Integrations.OUTGOING_WEBHOOK) {
- headerText = (
- <FormattedMessage
- id={'installed_outgoing_webhooks.header'}
- defaultMessage='Outgoing Webhooks'
- />
- );
- helpText = (
- <p>
- <FormattedHTMLMessage
- id='add_outgoing_webhook.doneHelp'
- defaultMessage='Your outgoing webhook has been set up. The following token will be sent in the outgoing payload. Please use it to verify the request came from your Mattermost team (see <a href=\"https://docs.mattermost.com/developer/webhooks-outgoing.html\">documentation</a> for further details).'
- />
- </p>
- );
- tokenText = (
- <p className='word-break--all'>
- <FormattedHTMLMessage
- id='add_outgoing_webhook.token'
- defaultMessage='<b>Token</b>: {token}'
- values={{
- token: IntegrationStore.getOutgoingWebhook(this.props.team.id, this.state.id).token
- }}
- />
- </p>
- );
- } else if (this.state.type === Constants.Integrations.OAUTH_APP) {
- let oauthApp = {};
- for (var i = 0; i < this.state.oauthApps.length; i++) {
- if (this.state.oauthApps[i].id === this.state.id) {
- oauthApp = this.state.oauthApps[i];
- break;
- }
- }
-
- if (oauthApp) {
- headerText = (
- <FormattedMessage
- id={'installed_oauth_apps.header'}
- defaultMessage='OAuth 2.0 Applications'
- />
- );
-
- helpText = [];
- helpText.push(
- <p key='add_oauth_app.doneHelp'>
- <FormattedHTMLMessage
- id='add_oauth_app.doneHelp'
- defaultMessage='Your OAuth 2.0 application has been set up. Please use the following Client ID and Client Secret when requesting authorization for your application (see <a href="https://docs.mattermost.com/developer/oauth-2-0-applications.html">documentation</a> for further details).'
- />
- </p>
- );
- helpText.push(
- <p key='add_oauth_app.clientId'>
- <FormattedHTMLMessage
- id='add_oauth_app.clientId'
- defaultMessage='<b>Client ID:</b> {id}'
- values={{
- id: this.state.id
- }}
- /> <br/>
- <FormattedHTMLMessage
- id='add_oauth_app.clientSecret'
- defaultMessage='<b>Client Secret:</b> {secret}'
- values={{
- secret: oauthApp.client_secret
- }}
- />
- </p>
- );
-
- helpText.push(
- <p key='add_oauth_app.doneUrlHelp'>
- <FormattedHTMLMessage
- id='add_oauth_app.doneUrlHelp'
- defaultMessage='The following are your authorized redirect URL(s).'
- />
- </p>
- );
-
- tokenText = (
- <p className='word-break--all'>
- <FormattedHTMLMessage
- id='add_oauth_app.url'
- defaultMessage='<b>URL(s)</b>: {url}'
- values={{
- url: oauthApp.callback_urls
- }}
- />
- </p>
- );
- }
- }
-
- return (
- <div className='backstage-content row'>
- <BackstageHeader>
- <Link to={'/' + this.props.team.name + '/integrations/' + this.state.type}>
- {headerText}
- </Link>
- <FormattedMessage
- id='integrations.add'
- defaultMessage='Add'
- />
- </BackstageHeader>
- <div className='backstage-form backstage-form__confirmation'>
- <h4 className='backstage-form__title'>
- <FormattedMessage
- id='integrations.successful'
- defaultMessage='Setup Successful'
- />
- </h4>
- {helpText}
- {tokenText}
- <div className='backstage-form__footer'>
- <Link
- className='btn btn-primary'
- type='submit'
- to={'/' + this.props.team.name + '/integrations/' + this.state.type}
- >
- <FormattedMessage
- id='integrations.done'
- defaultMessage='Done'
- />
- </Link>
- </div>
- </div>
- </div>
- );
- }
-}
diff --git a/webapp/components/integrations/components/confirm_integration/index.js b/webapp/components/integrations/components/confirm_integration/index.js
deleted file mode 100644
index fe7984f2b..000000000
--- a/webapp/components/integrations/components/confirm_integration/index.js
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import {connect} from 'react-redux';
-import {getCommands} from 'mattermost-redux/selectors/entities/integrations';
-
-import ConfirmIntegration from './confirm_integration.jsx';
-
-function mapStateToProps(state, ownProps) {
- return {
- ...ownProps,
- commands: getCommands(state)
- };
-}
-
-export default connect(mapStateToProps)(ConfirmIntegration); \ No newline at end of file
diff --git a/webapp/components/integrations/components/delete_integration.jsx b/webapp/components/integrations/components/delete_integration.jsx
deleted file mode 100644
index 592f415d6..000000000
--- a/webapp/components/integrations/components/delete_integration.jsx
+++ /dev/null
@@ -1,51 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import {FormattedMessage} from 'react-intl';
-
-import DeleteModalTrigger from '../../delete_modal_trigger.jsx';
-
-export default class DeleteIntegration extends DeleteModalTrigger {
- get triggerTitle() {
- return (
- <FormattedMessage
- id='installed_integrations.delete'
- defaultMessage='Delete'
- />
- );
- }
-
- get modalTitle() {
- return (
- <FormattedMessage
- id='integrations.delete.confirm.title'
- defaultMessage='Delete Integration'
- />
- );
- }
-
- get modalMessage() {
- return (
- <div className='alert alert-warning'>
- <i className='fa fa-warning fa-margin--right'/>
- <FormattedMessage
- id={this.props.messageId}
- defaultMessage='This action permanently deletes the integration and breaks any integrations using it. Are you sure you want to delete it?'
- />
- </div>
- );
- }
-
- get modalConfirmButton() {
- return (
- <FormattedMessage
- id='integrations.delete.confirm.button'
- defaultMessage='Delete'
- />
- );
- }
-}
-
-DeleteIntegration.propTypes = {
- messageId: PropTypes.string.isRequired,
- onDelete: PropTypes.func.isRequired
-};
diff --git a/webapp/components/integrations/components/edit_command/edit_command.jsx b/webapp/components/integrations/components/edit_command/edit_command.jsx
deleted file mode 100644
index 588047fb3..000000000
--- a/webapp/components/integrations/components/edit_command/edit_command.jsx
+++ /dev/null
@@ -1,727 +0,0 @@
-// Copyright (c) 2016-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 {browserHistory, Link} from 'react-router/es6';
-import Constants from 'utils/constants.jsx';
-import * as Utils from 'utils/utils.jsx';
-
-import FormError from 'components/form_error.jsx';
-import SpinnerButton from 'components/spinner_button.jsx';
-import ConfirmModal from 'components/confirm_modal.jsx';
-import BackstageHeader from 'components/backstage/components/backstage_header.jsx';
-
-const REQUEST_POST = 'P';
-const REQUEST_GET = 'G';
-
-export default class EditCommand extends React.PureComponent {
- static propTypes = {
-
- /**
- * The current team
- */
- team: PropTypes.object.isRequired,
-
- /**
- * The id of the command to edit
- */
- commandId: PropTypes.string.isRequired,
-
- /**
- * Installed slash commands to display
- */
- commands: PropTypes.object,
-
- /**
- * The request state for editCommand action. Contains status and error
- */
- editCommandRequest: PropTypes.object.isRequired,
-
- actions: PropTypes.shape({
-
- /**
- * The function to call to fetch team commands
- */
- getCustomTeamCommands: PropTypes.func.isRequired,
-
- /**
- * The function to call to edit command
- */
- editCommand: PropTypes.func.isRequired
- }).isRequired
- }
-
- constructor(props) {
- super(props);
-
- this.originalCommand = null;
- this.newCommand = null;
-
- this.state = {
- displayName: '',
- description: '',
- trigger: '',
- url: '',
- method: REQUEST_POST,
- username: '',
- iconUrl: '',
- autocomplete: false,
- autocompleteHint: '',
- autocompleteDescription: '',
- saving: false,
- serverError: '',
- clientError: null,
- showConfirmModal: false,
- loading: true
- };
- }
-
- componentDidMount() {
- if (window.mm_config.EnableCommands === 'true') {
- this.props.actions.getCustomTeamCommands(this.props.team.id).then(
- () => {
- this.originalCommand = Object.values(this.props.commands).filter((command) => command.id === this.props.commandId)[0];
- this.setState({
- displayName: this.originalCommand.display_name,
- description: this.originalCommand.description,
- trigger: this.originalCommand.trigger,
- url: this.originalCommand.url,
- method: this.originalCommand.method,
- username: this.originalCommand.username,
- iconUrl: this.originalCommand.icon_url,
- autocomplete: this.originalCommand.auto_complete,
- autocompleteHint: this.originalCommand.auto_complete_hint,
- autocompleteDescription: this.originalCommand.auto_complete_desc,
- loading: false
- });
- }
- );
- }
- }
-
- handleConfirmModal = () => {
- this.setState({showConfirmModal: true});
- }
-
- confirmModalDismissed = () => {
- this.setState({showConfirmModal: false});
- }
-
- submitCommand = async () => {
- const data = await this.props.actions.editCommand(this.newCommand);
-
- if (data) {
- browserHistory.push(`/${this.props.team.name}/integrations/commands`);
- return;
- }
-
- if (this.props.editCommandRequest.error) {
- this.setState({
- saving: false,
- serverError: this.props.editCommandRequest.error.message
- });
- }
- }
-
- handleUpdate = async () => {
- this.setState({
- saving: true,
- serverError: '',
- clientError: ''
- });
-
- await this.submitCommand();
- }
-
- handleSubmit = async (e) => {
- e.preventDefault();
-
- if (this.state.saving) {
- return;
- }
-
- this.setState({
- saving: true,
- serverError: '',
- clientError: ''
- });
-
- let triggerWord = this.state.trigger.trim().toLowerCase();
- if (triggerWord.indexOf('/') === 0) {
- triggerWord = triggerWord.substr(1);
- }
-
- const command = {
- display_name: this.state.displayName,
- description: this.state.description,
- trigger: triggerWord,
- url: this.state.url.trim(),
- method: this.state.method,
- username: this.state.username,
- icon_url: this.state.iconUrl,
- auto_complete: this.state.autocomplete,
- team_id: this.props.team.id
- };
-
- if (this.originalCommand.id) {
- command.id = this.originalCommand.id;
- }
-
- if (command.auto_complete) {
- command.auto_complete_desc = this.state.autocompleteDescription;
- command.auto_complete_hint = this.state.autocompleteHint;
- }
-
- if (!command.trigger) {
- this.setState({
- saving: false,
- clientError: (
- <FormattedMessage
- id='add_command.triggerRequired'
- defaultMessage='A trigger word is required'
- />
- )
- });
-
- return;
- }
-
- if (command.trigger.indexOf('/') === 0) {
- this.setState({
- saving: false,
- clientError: (
- <FormattedMessage
- id='add_command.triggerInvalidSlash'
- defaultMessage='A trigger word cannot begin with a /'
- />
- )
- });
-
- return;
- }
-
- if (command.trigger.indexOf(' ') !== -1) {
- this.setState({
- saving: false,
- clientError: (
- <FormattedMessage
- id='add_command.triggerInvalidSpace'
- defaultMessage='A trigger word must not contain spaces'
- />
- )
- });
- return;
- }
-
- if (command.trigger.length < Constants.MIN_TRIGGER_LENGTH ||
- command.trigger.length > Constants.MAX_TRIGGER_LENGTH) {
- this.setState({
- saving: false,
- clientError: (
- <FormattedMessage
- id='add_command.triggerInvalidLength'
- defaultMessage='A trigger word must contain between {min} and {max} characters'
- values={{
- min: Constants.MIN_TRIGGER_LENGTH,
- max: Constants.MAX_TRIGGER_LENGTH
- }}
- />
- )
- });
-
- return;
- }
-
- if (!command.url) {
- this.setState({
- saving: false,
- clientError: (
- <FormattedMessage
- id='add_command.urlRequired'
- defaultMessage='A request URL is required'
- />
- )
- });
-
- return;
- }
-
- this.newCommand = command;
-
- if (this.originalCommand.url !== this.newCommand.url ||
- this.originalCommand.trigger !== this.newCommand.trigger ||
- this.originalCommand.method !== this.newCommand.method) {
- this.handleConfirmModal();
- this.setState({
- saving: false
- });
- } else {
- await this.submitCommand();
- }
- }
-
- updateDisplayName = (e) => {
- this.setState({
- displayName: e.target.value
- });
- }
-
- updateDescription = (e) => {
- this.setState({
- description: e.target.value
- });
- }
-
- updateTrigger = (e) => {
- this.setState({
- trigger: e.target.value
- });
- }
-
- updateUrl = (e) => {
- this.setState({
- url: e.target.value
- });
- }
-
- updateMethod = (e) => {
- this.setState({
- method: e.target.value
- });
- }
-
- updateUsername = (e) => {
- this.setState({
- username: e.target.value
- });
- }
-
- updateIconUrl = (e) => {
- this.setState({
- iconUrl: e.target.value
- });
- }
-
- updateAutocomplete = (e) => {
- this.setState({
- autocomplete: e.target.checked
- });
- }
-
- updateAutocompleteHint = (e) => {
- this.setState({
- autocompleteHint: e.target.value
- });
- }
-
- updateAutocompleteDescription = (e) => {
- this.setState({
- autocompleteDescription: e.target.value
- });
- }
-
- render() {
- const confirmButton = (
- <FormattedMessage
- id='update_command.update'
- defaultMessage='Update'
- />
- );
-
- const confirmTitle = (
- <FormattedMessage
- id='update_command.confirm'
- defaultMessage='Edit Slash Command'
- />
- );
-
- const confirmMessage = (
- <FormattedMessage
- id='update_command.question'
- defaultMessage='Your changes may break the existing slash command. Are you sure you would like to update it?'
- />
- );
-
- let autocompleteFields = null;
- if (this.state.autocomplete) {
- autocompleteFields = [(
- <div
- key='autocompleteHint'
- className='form-group'
- >
- <label
- className='control-label col-sm-4'
- htmlFor='autocompleteHint'
- >
- <FormattedMessage
- id='add_command.autocompleteHint'
- defaultMessage='Autocomplete Hint'
- />
- </label>
- <div className='col-md-5 col-sm-8'>
- <input
- id='autocompleteHint'
- type='text'
- maxLength='1024'
- className='form-control'
- value={this.state.autocompleteHint}
- onChange={this.updateAutocompleteHint}
- placeholder={Utils.localizeMessage('add_command.autocompleteHint.placeholder', 'Example: [Patient Name]')}
- />
- <div className='form__help'>
- <FormattedMessage
- id='add_command.autocompleteHint.help'
- defaultMessage='(Optional) Arguments associated with your slash command, displayed as help in the autocomplete list.'
- />
- </div>
- </div>
- </div>
- ),
- (
- <div
- key='autocompleteDescription'
- className='form-group'
- >
- <label
- className='control-label col-sm-4'
- htmlFor='autocompleteDescription'
- >
- <FormattedMessage
- id='add_command.autocompleteDescription'
- defaultMessage='Autocomplete Description'
- />
- </label>
- <div className='col-md-5 col-sm-8'>
- <input
- id='description'
- type='text'
- maxLength='128'
- className='form-control'
- value={this.state.autocompleteDescription}
- onChange={this.updateAutocompleteDescription}
- placeholder={Utils.localizeMessage('add_command.autocompleteDescription.placeholder', 'Example: "Returns search results for patient records"')}
- />
- <div className='form__help'>
- <FormattedMessage
- id='add_command.autocompleteDescription.help'
- defaultMessage='(Optional) Short description of slash command for the autocomplete list.'
- />
- </div>
- </div>
- </div>
- )];
- }
-
- return (
- <div className='backstage-content row'>
- <BackstageHeader>
- <Link to={'/' + this.props.team.name + '/integrations/commands'}>
- <FormattedMessage
- id='installed_command.header'
- defaultMessage='Slash Commands'
- />
- </Link>
- <FormattedMessage
- id='integrations.edit'
- defaultMessage='Edit'
- />
- </BackstageHeader>
- <div className='backstage-form'>
- <form
- className='form-horizontal'
- onSubmit={this.handleSubmit}
- >
- <div className='form-group'>
- <label
- className='control-label col-sm-4'
- htmlFor='displayName'
- >
- <FormattedMessage
- id='add_command.displayName'
- defaultMessage='Display Name'
- />
- </label>
- <div className='col-md-5 col-sm-8'>
- <input
- id='displayName'
- type='text'
- maxLength='64'
- className='form-control'
- value={this.state.displayName}
- onChange={this.updateDisplayName}
- />
- <div className='form__help'>
- <FormattedMessage
- id='add_command.displayName.help'
- defaultMessage='Display name for your slash command made of up to 64 characters.'
- />
- </div>
- </div>
- </div>
- <div className='form-group'>
- <label
- className='control-label col-sm-4'
- htmlFor='description'
- >
- <FormattedMessage
- id='add_command.description'
- defaultMessage='Description'
- />
- </label>
- <div className='col-md-5 col-sm-8'>
- <input
- id='description'
- type='text'
- maxLength='128'
- className='form-control'
- value={this.state.description}
- onChange={this.updateDescription}
- />
- <div className='form__help'>
- <FormattedMessage
- id='add_command.description.help'
- defaultMessage='Description for your incoming webhook.'
- />
- </div>
- </div>
- </div>
- <div className='form-group'>
- <label
- className='control-label col-sm-4'
- htmlFor='trigger'
- >
- <FormattedMessage
- id='add_command.trigger'
- defaultMessage='Command Trigger Word'
- />
- </label>
- <div className='col-md-5 col-sm-8'>
- <input
- id='trigger'
- type='text'
- maxLength={Constants.MAX_TRIGGER_LENGTH}
- className='form-control'
- value={this.state.trigger}
- onChange={this.updateTrigger}
- placeholder={Utils.localizeMessage('add_command.trigger.placeholder', 'Command trigger e.g. "hello" not including the slash')}
- />
- <div className='form__help'>
- <FormattedMessage
- id='add_command.trigger.help'
- defaultMessage='Trigger word must be unique, and cannot begin with a slash or contain any spaces.'
- />
- </div>
- <div className='form__help'>
- <FormattedMessage
- id='add_command.trigger.helpExamples'
- defaultMessage='Examples: client, employee, patient, weather'
- />
- </div>
- <div className='form__help'>
- <FormattedMessage
- id='add_command.trigger.helpReserved'
- defaultMessage='Reserved: {link}'
- values={{
- link: (
- <a
- href='https://docs.mattermost.com/help/messaging/executing-commands.html#built-in-commands'
- target='_blank'
- rel='noopener noreferrer'
- >
- <FormattedMessage
- id='add_command.trigger.helpReservedLinkText'
- defaultMessage='see list of built-in slash commands'
- />
- </a>
- )
- }}
- />
- </div>
- </div>
- </div>
- <div className='form-group'>
- <label
- className='control-label col-sm-4'
- htmlFor='url'
- >
- <FormattedMessage
- id='add_command.url'
- defaultMessage='Request URL'
- />
- </label>
- <div className='col-md-5 col-sm-8'>
- <input
- id='url'
- type='text'
- maxLength='1024'
- className='form-control'
- value={this.state.url}
- onChange={this.updateUrl}
- placeholder={Utils.localizeMessage('add_command.url.placeholder', 'Must start with http:// or https://')}
- />
- <div className='form__help'>
- <FormattedMessage
- id='add_command.url.help'
- defaultMessage='The callback URL to receive the HTTP POST or GET event request when the slash command is run.'
- />
- </div>
- </div>
- </div>
- <div className='form-group'>
- <label
- className='control-label col-sm-4'
- htmlFor='method'
- >
- <FormattedMessage
- id='add_command.method'
- defaultMessage='Request Method'
- />
- </label>
- <div className='col-md-5 col-sm-8'>
- <select
- id='method'
- className='form-control'
- value={this.state.method}
- onChange={this.updateMethod}
- >
- <option value={REQUEST_POST}>
- {Utils.localizeMessage('add_command.method.post', 'POST')}
- </option>
- <option value={REQUEST_GET}>
- {Utils.localizeMessage('add_command.method.get', 'GET')}
- </option>
- </select>
- <div className='form__help'>
- <FormattedMessage
- id='add_command.method.help'
- defaultMessage='The type of command request issued to the Request URL.'
- />
- </div>
- </div>
- </div>
- <div className='form-group'>
- <label
- className='control-label col-sm-4'
- htmlFor='username'
- >
- <FormattedMessage
- id='add_command.username'
- defaultMessage='Response Username'
- />
- </label>
- <div className='col-md-5 col-sm-8'>
- <input
- id='username'
- type='text'
- maxLength='64'
- className='form-control'
- value={this.state.username}
- onChange={this.updateUsername}
- placeholder={Utils.localizeMessage('add_command.username.placeholder', 'Username')}
- />
- <div className='form__help'>
- <FormattedMessage
- id='add_command.username.help'
- defaultMessage='(Optional) Choose a username override for responses for this slash command. Usernames can consist of up to 22 characters consisting of lowercase letters, numbers and they symbols "-", "_", and "." .'
- />
- </div>
- </div>
- </div>
- <div className='form-group'>
- <label
- className='control-label col-sm-4'
- htmlFor='iconUrl'
- >
- <FormattedMessage
- id='add_command.iconUrl'
- defaultMessage='Response Icon'
- />
- </label>
- <div className='col-md-5 col-sm-8'>
- <input
- id='iconUrl'
- type='text'
- maxLength='1024'
- className='form-control'
- value={this.state.iconUrl}
- onChange={this.updateIconUrl}
- placeholder={Utils.localizeMessage('add_command.iconUrl.placeholder', 'https://www.example.com/myicon.png')}
- />
- <div className='form__help'>
- <FormattedMessage
- id='add_command.iconUrl.help'
- defaultMessage='(Optional) Choose a profile picture override for the post responses to this slash command. Enter the URL of a .png or .jpg file at least 128 pixels by 128 pixels.'
- />
- </div>
- </div>
- </div>
- <div className='form-group'>
- <label
- className='control-label col-sm-4'
- htmlFor='autocomplete'
- >
- <FormattedMessage
- id='add_command.autocomplete'
- defaultMessage='Autocomplete'
- />
- </label>
- <div className='col-md-5 col-sm-8 checkbox'>
- <input
- id='autocomplete'
- type='checkbox'
- checked={this.state.autocomplete}
- onChange={this.updateAutocomplete}
- />
- <div className='form__help'>
- <FormattedMessage
- id='add_command.autocomplete.help'
- defaultMessage='(Optional) Show slash command in autocomplete list.'
- />
- </div>
- </div>
- </div>
- {autocompleteFields}
- <div className='backstage-form__footer'>
- <FormError
- type='backstage'
- errors={[this.state.serverError, this.state.clientError]}
- />
- <Link
- className='btn btn-sm'
- to={'/' + this.props.team.name + '/integrations/commands'}
- >
- <FormattedMessage
- id='add_command.cancel'
- defaultMessage='Cancel'
- />
- </Link>
- <SpinnerButton
- className='btn btn-primary'
- type='submit'
- spinning={this.state.saving}
- onClick={this.handleSubmit}
- disabled={this.state.loading}
- >
- <FormattedMessage
- id='edit_command.save'
- defaultMessage='Update'
- />
- </SpinnerButton>
- <ConfirmModal
- title={confirmTitle}
- message={confirmMessage}
- confirmButtonText={confirmButton}
- show={this.state.showConfirmModal}
- onConfirm={this.handleUpdate}
- onCancel={this.confirmModalDismissed}
- />
- </div>
- </form>
- </div>
- </div>
- );
- }
-}
diff --git a/webapp/components/integrations/components/edit_command/index.js b/webapp/components/integrations/components/edit_command/index.js
deleted file mode 100644
index 2a8257113..000000000
--- a/webapp/components/integrations/components/edit_command/index.js
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import {connect} from 'react-redux';
-import {bindActionCreators} from 'redux';
-import {getCustomTeamCommands, editCommand} from 'mattermost-redux/actions/integrations';
-import {getCommands} from 'mattermost-redux/selectors/entities/integrations';
-
-import EditCommand from './edit_command.jsx';
-
-function mapStateToProps(state, ownProps) {
- const commandId = ownProps.location.query.id;
-
- return {
- ...ownProps,
- commandId,
- commands: getCommands(state),
- editCommandRequest: state.requests.integrations.editCommand
- };
-}
-
-function mapDispatchToProps(dispatch) {
- return {
- actions: bindActionCreators({
- getCustomTeamCommands,
- editCommand
- }, dispatch)
- };
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(EditCommand);
diff --git a/webapp/components/integrations/components/edit_incoming_webhook/edit_incoming_webhook.jsx b/webapp/components/integrations/components/edit_incoming_webhook/edit_incoming_webhook.jsx
deleted file mode 100644
index 35d8983a2..000000000
--- a/webapp/components/integrations/components/edit_incoming_webhook/edit_incoming_webhook.jsx
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import {browserHistory} from 'react-router/es6';
-import LoadingScreen from 'components/loading_screen.jsx';
-
-import AbstractIncomingWebhook from 'components/integrations/components/abstract_incoming_webhook.jsx';
-
-import React from 'react';
-import PropTypes from 'prop-types';
-
-const HEADER = {id: 'integrations.edit', defaultMessage: 'Edit'};
-const FOOTER = {id: 'update_incoming_webhook.update', defaultMessage: 'Update'};
-
-export default class EditIncomingWebhook extends React.PureComponent {
- static propTypes = {
-
- /**
- * The current team
- */
- team: PropTypes.object.isRequired,
-
- /**
- * The incoming webhook to edit
- */
- hook: PropTypes.object,
-
- /**
- * The id of the incoming webhook to edit
- */
- hookId: PropTypes.string.isRequired,
-
- /**
- * The request state for updateIncomingHook action. Contains status and error
- */
- updateIncomingHookRequest: PropTypes.object.isRequired,
-
- actions: PropTypes.shape({
-
- /**
- * The function to call to update an incoming webhook
- */
- updateIncomingHook: PropTypes.func.isRequired,
-
- /**
- * The function to call to get an incoming webhook
- */
- getIncomingHook: PropTypes.func.isRequired
- }).isRequired
- }
-
- constructor(props) {
- super(props);
-
- this.state = {
- showConfirmModal: false,
- serverError: ''
- };
- }
-
- componentDidMount() {
- if (window.mm_config.EnableIncomingWebhooks === 'true') {
- this.props.actions.getIncomingHook(this.props.hookId);
- }
- }
-
- editIncomingHook = async (hook) => {
- this.newHook = hook;
-
- if (this.props.hook.id) {
- hook.id = this.props.hook.id;
- }
-
- if (this.props.hook.token) {
- hook.token = this.props.hook.token;
- }
-
- await this.submitHook();
- }
-
- submitHook = async () => {
- this.setState({serverError: ''});
-
- const data = await this.props.actions.updateIncomingHook(this.newHook);
-
- if (data) {
- browserHistory.push(`/${this.props.team.name}/integrations/incoming_webhooks`);
- return;
- }
-
- if (this.props.updateIncomingHookRequest.error) {
- this.setState({serverError: this.props.updateIncomingHookRequest.error.message});
- }
- }
-
- render() {
- if (!this.props.hook) {
- return <LoadingScreen/>;
- }
-
- return (
- <AbstractIncomingWebhook
- team={this.props.team}
- header={HEADER}
- footer={FOOTER}
- action={this.editIncomingHook}
- serverError={this.state.serverError}
- initialHook={this.props.hook}
- />
- );
- }
-}
diff --git a/webapp/components/integrations/components/edit_incoming_webhook/index.js b/webapp/components/integrations/components/edit_incoming_webhook/index.js
deleted file mode 100644
index a391a98a6..000000000
--- a/webapp/components/integrations/components/edit_incoming_webhook/index.js
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import {connect} from 'react-redux';
-import {bindActionCreators} from 'redux';
-import {updateIncomingHook, getIncomingHook} from 'mattermost-redux/actions/integrations';
-
-import EditIncomingWebhook from './edit_incoming_webhook.jsx';
-
-function mapStateToProps(state, ownProps) {
- const hookId = ownProps.location.query.id;
-
- return {
- ...ownProps,
- hookId,
- hook: state.entities.integrations.incomingHooks[hookId],
- updateIncomingHookRequest: state.requests.integrations.createIncomingHook
- };
-}
-
-function mapDispatchToProps(dispatch) {
- return {
- actions: bindActionCreators({
- updateIncomingHook,
- getIncomingHook
- }, dispatch)
- };
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(EditIncomingWebhook); \ No newline at end of file
diff --git a/webapp/components/integrations/components/edit_outgoing_webhook/edit_outgoing_webhook.jsx b/webapp/components/integrations/components/edit_outgoing_webhook/edit_outgoing_webhook.jsx
deleted file mode 100644
index 9b2dbff0a..000000000
--- a/webapp/components/integrations/components/edit_outgoing_webhook/edit_outgoing_webhook.jsx
+++ /dev/null
@@ -1,169 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import AbstractOutgoingWebhook from 'components/integrations/components/abstract_outgoing_webhook.jsx';
-import ConfirmModal from 'components/confirm_modal.jsx';
-import LoadingScreen from 'components/loading_screen.jsx';
-
-import React from 'react';
-import PropTypes from 'prop-types';
-import {browserHistory} from 'react-router/es6';
-import {FormattedMessage} from 'react-intl';
-
-const HEADER = {id: 'integrations.edit', defaultMessage: 'Edit'};
-const FOOTER = {id: 'update_outgoing_webhook.update', defaultMessage: 'Update'};
-
-export default class EditOutgoingWebhook extends React.PureComponent {
- static propTypes = {
-
- /**
- * The current team
- */
- team: PropTypes.object.isRequired,
-
- /**
- * The outgoing webhook to edit
- */
- hook: PropTypes.object,
-
- /**
- * The id of the outgoing webhook to edit
- */
- hookId: PropTypes.string.isRequired,
-
- /**
- * The request state for updateOutgoingHook action. Contains status and error
- */
- updateOutgoingHookRequest: PropTypes.object.isRequired,
-
- actions: PropTypes.shape({
-
- /**
- * The function to call to update an outgoing webhook
- */
- updateOutgoingHook: PropTypes.func.isRequired,
-
- /**
- * The function to call to get an outgoing webhook
- */
- getOutgoingHook: PropTypes.func.isRequired
- }).isRequired
- }
-
- constructor(props) {
- super(props);
-
- this.state = {
- showConfirmModal: false,
- serverError: ''
- };
- }
-
- componentDidMount() {
- if (window.mm_config.EnableOutgoingWebhooks === 'true') {
- this.props.actions.getOutgoingHook(this.props.hookId);
- }
- }
-
- editOutgoingHook = async (hook) => {
- this.newHook = hook;
-
- if (this.props.hook.id) {
- hook.id = this.props.hook.id;
- }
-
- if (this.props.hook.token) {
- hook.token = this.props.hook.token;
- }
-
- const triggerWordsSame = (this.props.hook.trigger_words.length === hook.trigger_words.length) &&
- this.props.hook.trigger_words.every((v, i) => v === hook.trigger_words[i]);
-
- const callbackUrlsSame = (this.props.hook.callback_urls.length === hook.callback_urls.length) &&
- this.props.hook.callback_urls.every((v, i) => v === hook.callback_urls[i]);
-
- if (this.props.hook.content_type !== hook.content_type ||
- !triggerWordsSame || !callbackUrlsSame) {
- this.handleConfirmModal();
- } else {
- await this.submitHook();
- }
- }
-
- handleConfirmModal = () => {
- this.setState({showConfirmModal: true});
- }
-
- confirmModalDismissed = () => {
- this.setState({showConfirmModal: false});
- }
-
- submitHook = async () => {
- this.setState({serverError: ''});
-
- const data = await this.props.actions.updateOutgoingHook(this.newHook);
-
- if (data) {
- browserHistory.push(`/${this.props.team.name}/integrations/outgoing_webhooks`);
- return;
- }
-
- this.setState({showConfirmModal: false});
-
- if (this.props.updateOutgoingHookRequest.error) {
- this.setState({serverError: this.props.updateOutgoingHookRequest.error.message});
- }
- }
-
- renderExtra = () => {
- const confirmButton = (
- <FormattedMessage
- id='update_outgoing_webhook.update'
- defaultMessage='Update'
- />
- );
-
- const confirmTitle = (
- <FormattedMessage
- id='update_outgoing_webhook.confirm'
- defaultMessage='Edit Outgoing Webhook'
- />
- );
-
- const confirmMessage = (
- <FormattedMessage
- id='update_outgoing_webhook.question'
- defaultMessage='Your changes may break the existing outgoing webhook. Are you sure you would like to update it?'
- />
- );
-
- return (
- <ConfirmModal
- title={confirmTitle}
- message={confirmMessage}
- confirmButtonText={confirmButton}
- show={this.state.showConfirmModal}
- onConfirm={this.submitHook}
- onCancel={this.confirmModalDismissed}
- />
- );
- }
-
- render() {
- if (!this.props.hook) {
- return <LoadingScreen/>;
- }
-
- return (
- <AbstractOutgoingWebhook
- team={this.props.team}
- header={HEADER}
- footer={FOOTER}
- renderExtra={this.renderExtra()}
- action={this.editOutgoingHook}
- serverError={this.state.serverError}
- initialHook={this.props.hook}
- />
- );
- }
-}
diff --git a/webapp/components/integrations/components/edit_outgoing_webhook/index.js b/webapp/components/integrations/components/edit_outgoing_webhook/index.js
deleted file mode 100644
index a526ac76c..000000000
--- a/webapp/components/integrations/components/edit_outgoing_webhook/index.js
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import {connect} from 'react-redux';
-import {bindActionCreators} from 'redux';
-import {updateOutgoingHook, getOutgoingHook} from 'mattermost-redux/actions/integrations';
-
-import EditOutgoingWebhook from './edit_outgoing_webhook.jsx';
-
-function mapStateToProps(state, ownProps) {
- const hookId = ownProps.location.query.id;
-
- return {
- ...ownProps,
- hookId,
- hook: state.entities.integrations.outgoingHooks[hookId],
- updateOutgoingHookRequest: state.requests.integrations.createOutgoingHook
- };
-}
-
-function mapDispatchToProps(dispatch) {
- return {
- actions: bindActionCreators({
- updateOutgoingHook,
- getOutgoingHook
- }, dispatch)
- };
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(EditOutgoingWebhook);
diff --git a/webapp/components/integrations/components/installed_command.jsx b/webapp/components/integrations/components/installed_command.jsx
deleted file mode 100644
index 1470712b0..000000000
--- a/webapp/components/integrations/components/installed_command.jsx
+++ /dev/null
@@ -1,176 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-import PropTypes from 'prop-types';
-import {Link} from 'react-router';
-import {FormattedMessage} from 'react-intl';
-
-import DeleteIntegration from './delete_integration.jsx';
-
-export default class InstalledCommand extends React.PureComponent {
- static propTypes = {
-
- /**
- * The team data
- */
- team: PropTypes.object.isRequired,
-
- /**
- * Installed slash command to display
- */
- command: PropTypes.object.isRequired,
-
- /**
- * The function to call when Regenerate Token link is clicked
- */
- onRegenToken: PropTypes.func.isRequired,
-
- /**
- * The function to call when Delete link is clicked
- */
- onDelete: PropTypes.func.isRequired,
-
- /**
- * Set to filter command, comes from BackstageList
- */
- filter: PropTypes.string,
-
- /**
- * The creator user data
- */
- creator: PropTypes.object.isRequired,
-
- /**
- * Set to show edit link
- */
- canChange: PropTypes.bool.isRequired
- }
-
- handleRegenToken = (e) => {
- e.preventDefault();
-
- this.props.onRegenToken(this.props.command);
- }
-
- handleDelete = () => {
- this.props.onDelete(this.props.command);
- }
-
- matchesFilter(command, filter) {
- if (!filter) {
- return true;
- }
-
- return command.display_name.toLowerCase().indexOf(filter) !== -1 ||
- command.description.toLowerCase().indexOf(filter) !== -1 ||
- command.trigger.toLowerCase().indexOf(filter) !== -1;
- }
-
- render() {
- const command = this.props.command;
- const filter = this.props.filter ? this.props.filter.toLowerCase() : '';
-
- if (!this.matchesFilter(command, filter)) {
- return null;
- }
-
- let name;
-
- if (command.display_name) {
- name = command.display_name;
- } else {
- name = (
- <FormattedMessage
- id='installed_commands.unnamed_command'
- defaultMessage='Unnamed Slash Command'
- />
- );
- }
-
- let description = null;
- if (command.description) {
- description = (
- <div className='item-details__row'>
- <span className='item-details__description'>
- {command.description}
- </span>
- </div>
- );
- }
-
- let trigger = '- /' + command.trigger;
- if (command.auto_complete && command.auto_complete_hint) {
- trigger += ' ' + command.auto_complete_hint;
- }
-
- let actions = null;
- if (this.props.canChange) {
- actions = (
- <div className='item-actions'>
- <a
- href='#'
- onClick={this.handleRegenToken}
- >
- <FormattedMessage
- id='installed_integrations.regenToken'
- defaultMessage='Regenerate Token'
- />
- </a>
- {' - '}
- <Link to={`/${this.props.team.name}/integrations/commands/edit?id=${command.id}`}>
- <FormattedMessage
- id='installed_integrations.edit'
- defaultMessage='Edit'
- />
- </Link>
- {' - '}
- <DeleteIntegration
- messageId='installed_commands.delete.confirm'
- onDelete={this.handleDelete}
- />
- </div>
- );
- }
-
- return (
- <div className='backstage-list__item'>
- <div className='item-details'>
- <div className='item-details__row'>
- <span className='item-details__name'>
- {name}
- </span>
- <span className='item-details__trigger'>
- {trigger}
- </span>
- </div>
- {description}
- <div className='item-details__row'>
- <span className='item-details__token'>
- <FormattedMessage
- id='installed_integrations.token'
- defaultMessage='Token: {token}'
- values={{
- token: command.token
- }}
- />
- </span>
- </div>
- <div className='item-details__row'>
- <span className='item-details__creation'>
- <FormattedMessage
- id='installed_integrations.creation'
- defaultMessage='Created by {creator} on {createAt, date, full}'
- values={{
- creator: this.props.creator.username,
- createAt: command.create_at
- }}
- />
- </span>
- </div>
- </div>
- {actions}
- </div>
- );
- }
-}
diff --git a/webapp/components/integrations/components/installed_commands/index.js b/webapp/components/integrations/components/installed_commands/index.js
deleted file mode 100644
index b8fb9b8bd..000000000
--- a/webapp/components/integrations/components/installed_commands/index.js
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import {connect} from 'react-redux';
-import {bindActionCreators} from 'redux';
-import {regenCommandToken, deleteCommand} from 'mattermost-redux/actions/integrations';
-
-import InstalledCommands from './installed_commands.jsx';
-
-function mapStateToProps(state, ownProps) {
- return {
- ...ownProps
- };
-}
-
-function mapDispatchToProps(dispatch) {
- return {
- actions: bindActionCreators({
- regenCommandToken,
- deleteCommand
- }, dispatch)
- };
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(InstalledCommands); \ No newline at end of file
diff --git a/webapp/components/integrations/components/installed_commands/installed_commands.jsx b/webapp/components/integrations/components/installed_commands/installed_commands.jsx
deleted file mode 100644
index 7085afdc4..000000000
--- a/webapp/components/integrations/components/installed_commands/installed_commands.jsx
+++ /dev/null
@@ -1,160 +0,0 @@
-// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import BackstageList from 'components/backstage/components/backstage_list.jsx';
-import InstalledCommand from '../installed_command.jsx';
-
-import * as Utils from 'utils/utils.jsx';
-
-import PropTypes from 'prop-types';
-
-import React from 'react';
-import {FormattedMessage} from 'react-intl';
-
-export default class InstalledCommands extends React.PureComponent {
- static propTypes = {
-
- /**
- * The team object
- */
- team: PropTypes.object,
-
- /**
- * The user object
- */
- user: PropTypes.object,
-
- /**
- * The users collection
- */
- users: PropTypes.object,
-
- /**
- * Installed slash commands to display
- */
- commands: PropTypes.array,
-
- /**
- * Set whether to show the loading... animation or not
- */
- loading: PropTypes.bool,
-
- /**
- * Set to allow changes to installed slash commands
- */
- isAdmin: PropTypes.bool,
-
- actions: PropTypes.shape({
-
- /**
- * The function to call when Regenerate Token link is clicked
- */
- regenCommandToken: PropTypes.func.isRequired,
-
- /**
- * The function to call when Delete link is clicked
- */
- deleteCommand: PropTypes.func.isRequired
- }).isRequired
- }
-
- regenCommandToken = (command) => {
- this.props.actions.regenCommandToken(command.id);
- }
-
- deleteCommand = (command) => {
- this.props.actions.deleteCommand(command.id);
- }
-
- commandCompare(a, b) {
- let nameA = a.display_name;
- if (!nameA) {
- nameA = Utils.localizeMessage('installed_commands.unnamed_command', 'Unnamed Slash Command');
- }
-
- let nameB = b.display_name;
- if (!nameB) {
- nameB = Utils.localizeMessage('installed_commands.unnamed_command', 'Unnamed Slash Command');
- }
-
- return nameA.localeCompare(nameB);
- }
-
- render() {
- const commands = this.props.commands.sort(this.commandCompare).map((command) => {
- const canChange = this.props.isAdmin || this.props.user.id === command.creator_id;
-
- return (
- <InstalledCommand
- key={command.id}
- team={this.props.team}
- command={command}
- onRegenToken={this.regenCommandToken}
- onDelete={this.deleteCommand}
- creator={this.props.users[command.creator_id] || {}}
- canChange={canChange}
- />
- );
- });
-
- return (
- <BackstageList
- header={
- <FormattedMessage
- id='installed_commands.header'
- defaultMessage='Installed Slash Commands'
- />
- }
- addText={
- <FormattedMessage
- id='installed_commands.add'
- defaultMessage='Add Slash Command'
- />
- }
- addLink={'/' + this.props.team.name + '/integrations/commands/add'}
- emptyText={
- <FormattedMessage
- id='installed_commands.empty'
- defaultMessage='No slash commands found'
- />
- }
- helpText={
- <FormattedMessage
- id='installed_commands.help'
- defaultMessage='Use slash commands to connect external tools to Mattermost. {buildYourOwn} or visit the {appDirectory} to find self-hosted, third-party apps and integrations.'
- values={{
- buildYourOwn: (
- <a
- target='_blank'
- rel='noopener noreferrer'
- href='http://docs.mattermost.com/developer/slash-commands.html'
- >
- <FormattedMessage
- id='installed_commands.help.buildYourOwn'
- defaultMessage='Build your own'
- />
- </a>
- ),
- appDirectory: (
- <a
- target='_blank'
- rel='noopener noreferrer'
- href='https://about.mattermost.com/default-app-directory/'
- >
- <FormattedMessage
- id='installed_commands.help.appDirectory'
- defaultMessage='App Directory'
- />
- </a>
- )
- }}
- />
- }
- searchPlaceholder={Utils.localizeMessage('installed_commands.search', 'Search Slash Commands')}
- loading={this.props.loading}
- >
- {commands}
- </BackstageList>
- );
- }
-} \ No newline at end of file
diff --git a/webapp/components/integrations/components/installed_incoming_webhook.jsx b/webapp/components/integrations/components/installed_incoming_webhook.jsx
deleted file mode 100644
index 241205b3f..000000000
--- a/webapp/components/integrations/components/installed_incoming_webhook.jsx
+++ /dev/null
@@ -1,147 +0,0 @@
-import PropTypes from 'prop-types';
-
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import DeleteIntegration from './delete_integration.jsx';
-
-import ChannelStore from 'stores/channel_store.jsx';
-import {getSiteURL} from 'utils/url.jsx';
-
-import {FormattedMessage} from 'react-intl';
-import {Link} from 'react-router';
-
-export default class InstalledIncomingWebhook extends React.Component {
- static get propTypes() {
- return {
- incomingWebhook: PropTypes.object.isRequired,
- onDelete: PropTypes.func.isRequired,
- filter: PropTypes.string,
- creator: PropTypes.object.isRequired,
- canChange: PropTypes.bool.isRequired,
- team: PropTypes.object.isRequired
- };
- }
-
- constructor(props) {
- super(props);
-
- this.handleDelete = this.handleDelete.bind(this);
- }
-
- handleDelete() {
- this.props.onDelete(this.props.incomingWebhook);
- }
-
- matchesFilter(incomingWebhook, channel, filter) {
- if (!filter) {
- return true;
- }
-
- if (incomingWebhook.display_name.toLowerCase().indexOf(filter) !== -1 ||
- incomingWebhook.description.toLowerCase().indexOf(filter) !== -1) {
- return true;
- }
-
- if (incomingWebhook.channel_id) {
- if (channel && channel.name.toLowerCase().indexOf(filter) !== -1) {
- return true;
- }
- }
-
- return false;
- }
-
- render() {
- const incomingWebhook = this.props.incomingWebhook;
- const channel = ChannelStore.get(incomingWebhook.channel_id);
- const filter = this.props.filter ? this.props.filter.toLowerCase() : '';
-
- if (!this.matchesFilter(incomingWebhook, channel, filter)) {
- return null;
- }
-
- let displayName;
- if (incomingWebhook.display_name) {
- displayName = incomingWebhook.display_name;
- } else if (channel) {
- displayName = channel.display_name;
- } else {
- displayName = (
- <FormattedMessage
- id='installed_incoming_webhooks.unknown_channel'
- defaultMessage='A Private Webhook'
- />
- );
- }
-
- let description = null;
- if (incomingWebhook.description) {
- description = (
- <div className='item-details__row'>
- <span className='item-details__description'>
- {incomingWebhook.description}
- </span>
- </div>
- );
- }
-
- let actions = null;
- if (this.props.canChange) {
- actions = (
- <div className='item-actions'>
- <Link to={`/${this.props.team.name}/integrations/incoming_webhooks/edit?id=${incomingWebhook.id}`}>
- <FormattedMessage
- id='installed_integrations.edit'
- defaultMessage='Edit'
- />
- </Link>
- {' - '}
- <DeleteIntegration
- messageId='installed_incoming_webhooks.delete.confirm'
- onDelete={this.handleDelete}
- />
- </div>
- );
- }
-
- return (
- <div className='backstage-list__item'>
- <div className='item-details'>
- <div className='item-details__row'>
- <span className='item-details__name'>
- {displayName}
- </span>
- </div>
- {description}
- <div className='item-details__row'>
- <span className='item-details__url'>
- <FormattedMessage
- id='installed_integrations.url'
- defaultMessage='URL: {url}'
- values={{
- url: getSiteURL() + '/hooks/' + incomingWebhook.id
- }}
- />
- </span>
- </div>
- <div className='item-details__row'>
- <span className='item-details__creation'>
- <FormattedMessage
- id='installed_integrations.creation'
- defaultMessage='Created by {creator} on {createAt, date, full}'
- values={{
- creator: this.props.creator.username,
- createAt: incomingWebhook.create_at
- }}
- />
- </span>
- </div>
- </div>
- {actions}
- </div>
- );
- }
-}
diff --git a/webapp/components/integrations/components/installed_incoming_webhooks.jsx b/webapp/components/integrations/components/installed_incoming_webhooks.jsx
deleted file mode 100644
index 06fa217dc..000000000
--- a/webapp/components/integrations/components/installed_incoming_webhooks.jsx
+++ /dev/null
@@ -1,178 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import BackstageList from 'components/backstage/components/backstage_list.jsx';
-import InstalledIncomingWebhook from './installed_incoming_webhook.jsx';
-
-import ChannelStore from 'stores/channel_store.jsx';
-import IntegrationStore from 'stores/integration_store.jsx';
-import TeamStore from 'stores/team_store.jsx';
-import UserStore from 'stores/user_store.jsx';
-
-import {loadIncomingHooksForTeam, deleteIncomingHook} from 'actions/integration_actions.jsx';
-
-import * as Utils from 'utils/utils.jsx';
-
-import PropTypes from 'prop-types';
-
-import React from 'react';
-import {FormattedMessage} from 'react-intl';
-
-export default class InstalledIncomingWebhooks extends React.Component {
- static get propTypes() {
- return {
- team: PropTypes.object,
- user: PropTypes.object,
- isAdmin: PropTypes.bool
- };
- }
-
- constructor(props) {
- super(props);
-
- this.handleIntegrationChange = this.handleIntegrationChange.bind(this);
- this.handleUserChange = this.handleUserChange.bind(this);
- this.deleteIncomingWebhook = this.deleteIncomingWebhook.bind(this);
-
- const teamId = TeamStore.getCurrentId();
-
- this.state = {
- incomingWebhooks: IntegrationStore.getIncomingWebhooks(teamId),
- loading: !IntegrationStore.hasReceivedIncomingWebhooks(teamId),
- users: UserStore.getProfiles()
- };
- }
-
- componentDidMount() {
- IntegrationStore.addChangeListener(this.handleIntegrationChange);
- UserStore.addChangeListener(this.handleUserChange);
-
- if (window.mm_config.EnableIncomingWebhooks === 'true') {
- loadIncomingHooksForTeam(TeamStore.getCurrentId(), () => this.setState({loading: false}));
- }
- }
-
- componentWillUnmount() {
- IntegrationStore.removeChangeListener(this.handleIntegrationChange);
- UserStore.removeChangeListener(this.handleUserChange);
- }
-
- handleIntegrationChange() {
- const teamId = TeamStore.getCurrentId();
-
- this.setState({
- incomingWebhooks: IntegrationStore.getIncomingWebhooks(teamId)
- });
- }
-
- handleUserChange() {
- this.setState({
- users: UserStore.getProfiles()
- });
- }
-
- deleteIncomingWebhook(incomingWebhook) {
- deleteIncomingHook(incomingWebhook.id);
- }
-
- incomingWebhookCompare(a, b) {
- let displayNameA = a.display_name;
- if (!displayNameA) {
- const channelA = ChannelStore.get(a.channel_id);
- if (channelA) {
- displayNameA = channelA.display_name;
- } else {
- displayNameA = Utils.localizeMessage('installed_incoming_webhooks.unknown_channel', 'A Private Webhook');
- }
- }
-
- let displayNameB = b.display_name;
- if (!displayNameB) {
- const channelB = ChannelStore.get(b.channel_id);
- if (channelB) {
- displayNameB = channelB.display_name;
- } else {
- displayNameB = Utils.localizeMessage('installed_incoming_webhooks.unknown_channel', 'A Private Webhook');
- }
- }
-
- return displayNameA.localeCompare(displayNameB);
- }
-
- render() {
- const incomingWebhooks = this.state.incomingWebhooks.sort(this.incomingWebhookCompare).map((incomingWebhook) => {
- const canChange = this.props.isAdmin || this.props.user.id === incomingWebhook.user_id;
-
- return (
- <InstalledIncomingWebhook
- key={incomingWebhook.id}
- incomingWebhook={incomingWebhook}
- onDelete={this.deleteIncomingWebhook}
- creator={this.state.users[incomingWebhook.user_id] || {}}
- canChange={canChange}
- team={this.props.team}
- />
- );
- });
-
- return (
- <BackstageList
- header={
- <FormattedMessage
- id='installed_incoming_webhooks.header'
- defaultMessage='Installed Incoming Webhooks'
- />
- }
- addText={
- <FormattedMessage
- id='installed_incoming_webhooks.add'
- defaultMessage='Add Incoming Webhook'
- />
- }
- addLink={'/' + this.props.team.name + '/integrations/incoming_webhooks/add'}
- emptyText={
- <FormattedMessage
- id='installed_incoming_webhooks.empty'
- defaultMessage='No incoming webhooks found'
- />
- }
- helpText={
- <FormattedMessage
- id='installed_incoming_webhooks.help'
- defaultMessage='Use incoming webhooks to connect external tools to Mattermost. {buildYourOwn} or visit the {appDirectory} to find self-hosted, third-party apps and integrations.'
- values={{
- buildYourOwn: (
- <a
- target='_blank'
- rel='noopener noreferrer'
- href='http://docs.mattermost.com/developer/webhooks-incoming.html'
- >
- <FormattedMessage
- id='installed_incoming_webhooks.help.buildYourOwn'
- defaultMessage='Build your own'
- />
- </a>
- ),
- appDirectory: (
- <a
- target='_blank'
- rel='noopener noreferrer'
- href='https://about.mattermost.com/default-app-directory/'
- >
- <FormattedMessage
- id='installed_incoming_webhooks.help.appDirectory'
- defaultMessage='App Directory'
- />
- </a>
- )
- }}
- />
- }
- searchPlaceholder={Utils.localizeMessage('installed_incoming_webhooks.search', 'Search Incoming Webhooks')}
- loading={this.state.loading}
- >
- {incomingWebhooks}
- </BackstageList>
- );
- }
-}
diff --git a/webapp/components/integrations/components/installed_oauth_app.jsx b/webapp/components/integrations/components/installed_oauth_app.jsx
deleted file mode 100644
index bcb7a7c96..000000000
--- a/webapp/components/integrations/components/installed_oauth_app.jsx
+++ /dev/null
@@ -1,270 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-import PropTypes from 'prop-types';
-
-import * as Utils from 'utils/utils.jsx';
-
-import {FormattedMessage, FormattedHTMLMessage} from 'react-intl';
-import FormError from 'components/form_error.jsx';
-import DeleteIntegration from './delete_integration.jsx';
-
-const FAKE_SECRET = '***************';
-
-export default class InstalledOAuthApp extends React.PureComponent {
- static propTypes = {
-
- /**
- * The oauthApp data
- */
- oauthApp: PropTypes.object.isRequired,
-
- /**
- * The request state for regenOAuthAppSecret action. Contains status and error
- */
- regenOAuthAppSecretRequest: PropTypes.object.isRequired,
-
- /**
- * The function to call when Regenerate Secret link is clicked
- */
- onRegenerateSecret: PropTypes.func.isRequired,
-
- /**
- * The function to call when Delete link is clicked
- */
- onDelete: PropTypes.func.isRequired,
-
- /**
- * Set to filter OAuthApp
- */
- filter: PropTypes.string
- }
-
- constructor(props) {
- super(props);
-
- this.state = {
- clientSecret: FAKE_SECRET
- };
- }
-
- handleShowClientSecret = (e) => {
- if (e && e.preventDefault) {
- e.preventDefault();
- }
- this.setState({clientSecret: this.props.oauthApp.client_secret});
- }
-
- handleHideClientSecret = (e) => {
- e.preventDefault();
- this.setState({clientSecret: FAKE_SECRET});
- }
-
- handleRegenerate = (e) => {
- e.preventDefault();
- this.props.onRegenerateSecret(this.props.oauthApp.id).then(
- () => {
- const {error} = this.props.regenOAuthAppSecretRequest;
- if (error) {
- this.setState({error: error.message});
- } else {
- this.setState({error: null});
- this.handleShowClientSecret();
- }
- }
- );
- }
-
- handleDelete = () => {
- this.props.onDelete(this.props.oauthApp);
- }
-
- matchesFilter = (oauthApp, filter) => {
- if (!filter) {
- return true;
- }
-
- return oauthApp.name.toLowerCase().indexOf(filter) !== -1;
- }
-
- render() {
- const oauthApp = this.props.oauthApp;
- let error;
-
- if (this.state.error) {
- error = (
- <FormError
- error={this.state.error}
- />
- );
- }
-
- if (!this.matchesFilter(oauthApp, this.props.filter)) {
- return null;
- }
-
- let name;
- if (oauthApp.name) {
- name = oauthApp.name;
- } else {
- name = (
- <FormattedMessage
- id='installed_integrations.unnamed_oauth_app'
- defaultMessage='Unnamed OAuth 2.0 Application'
- />
- );
- }
-
- let description;
- if (oauthApp.description) {
- description = (
- <div className='item-details__row'>
- <span className='item-details__description'>
- {oauthApp.description}
- </span>
- </div>
- );
- }
-
- const urls = (
- <div className='item-details__row'>
- <span className='item-details__url'>
- <FormattedMessage
- id='installed_integrations.callback_urls'
- defaultMessage='Callback URLs: {urls}'
- values={{
- urls: oauthApp.callback_urls.join(', ')
- }}
- />
- </span>
- </div>
- );
-
- let isTrusted;
- if (oauthApp.is_trusted) {
- isTrusted = Utils.localizeMessage('installed_oauth_apps.trusted.yes', 'Yes');
- } else {
- isTrusted = Utils.localizeMessage('installed_oauth_apps.trusted.no', 'No');
- }
-
- let showHide;
- if (this.state.clientSecret === FAKE_SECRET) {
- showHide = (
- <a
- href='#'
- onClick={this.handleShowClientSecret}
- >
- <FormattedMessage
- id='installed_integrations.showSecret'
- defaultMessage='Show Secret'
- />
- </a>
- );
- } else {
- showHide = (
- <a
- href='#'
- onClick={this.handleHideClientSecret}
- >
- <FormattedMessage
- id='installed_integrations.hideSecret'
- defaultMessage='Hide Secret'
- />
- </a>
- );
- }
-
- const regen = (
- <a
- href='#'
- onClick={this.handleRegenerate}
- >
- <FormattedMessage
- id='installed_integrations.regenSecret'
- defaultMessage='Regenerate Secret'
- />
- </a>
- );
-
- let icon;
- if (oauthApp.icon_url) {
- icon = (
- <div className='integration__icon integration-list__icon'>
- <img src={oauthApp.icon_url}/>
- </div>
- );
- }
-
- return (
- <div className='backstage-list__item'>
- {icon}
- <div className='item-details'>
- <div className='item-details__row'>
- <span className='item-details__name'>
- {name}
- </span>
- </div>
- {error}
- {description}
- <div className='item-details__row'>
- <span className='item-details__url'>
- <FormattedHTMLMessage
- id='installed_oauth_apps.is_trusted'
- defaultMessage='Is Trusted: <strong>{isTrusted}</strong>'
- values={{
- isTrusted
- }}
- />
- </span>
- </div>
- <div className='item-details__row'>
- <span className='item-details__token'>
- <FormattedHTMLMessage
- id='installed_integrations.client_id'
- defaultMessage='Client ID: <strong>{clientId}</strong>'
- values={{
- clientId: oauthApp.id
- }}
- />
- </span>
- </div>
- <div className='item-details__row'>
- <span className='item-details__token'>
- <FormattedHTMLMessage
- id='installed_integrations.client_secret'
- defaultMessage='Client Secret: <strong>{clientSecret}</strong>'
- values={{
- clientSecret: this.state.clientSecret
- }}
- />
- </span>
- </div>
- {urls}
- <div className='item-details__row'>
- <span className='item-details__creation'>
- <FormattedMessage
- id='installed_integrations.creation'
- defaultMessage='Created by {creator} on {createAt, date, full}'
- values={{
- creator: Utils.displayUsername(oauthApp.creator_id),
- createAt: oauthApp.create_at
- }}
- />
- </span>
- </div>
- </div>
- <div className='item-actions'>
- {showHide}
- {' - '}
- {regen}
- {' - '}
- <DeleteIntegration
- messageId='installed_oauth_apps.delete.confirm'
- onDelete={this.handleDelete}
- />
- </div>
- </div>
- );
- }
-} \ No newline at end of file
diff --git a/webapp/components/integrations/components/installed_oauth_apps/index.js b/webapp/components/integrations/components/installed_oauth_apps/index.js
deleted file mode 100644
index bfeed6d66..000000000
--- a/webapp/components/integrations/components/installed_oauth_apps/index.js
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import {connect} from 'react-redux';
-import {bindActionCreators} from 'redux';
-import * as Actions from 'mattermost-redux/actions/integrations';
-import {getOAuthApps} from 'mattermost-redux/selectors/entities/integrations';
-import {isCurrentUserSystemAdmin} from 'mattermost-redux/selectors/entities/users';
-
-import InstalledOAuthApps from './installed_oauth_apps.jsx';
-
-function mapStateToProps(state, ownProps) {
- return {
- ...ownProps,
- oauthApps: getOAuthApps(state),
- isSystemAdmin: isCurrentUserSystemAdmin(state),
- regenOAuthAppSecretRequest: state.requests.integrations.updateOAuthApp
- };
-}
-
-function mapDispatchToProps(dispatch) {
- return {
- actions: bindActionCreators({
- getOAuthApps: Actions.getOAuthApps,
- regenOAuthAppSecret: Actions.regenOAuthAppSecret,
- deleteOAuthApp: Actions.deleteOAuthApp
- }, dispatch)
- };
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(InstalledOAuthApps); \ No newline at end of file
diff --git a/webapp/components/integrations/components/installed_oauth_apps/installed_oauth_apps.jsx b/webapp/components/integrations/components/installed_oauth_apps/installed_oauth_apps.jsx
deleted file mode 100644
index 4cd27ab57..000000000
--- a/webapp/components/integrations/components/installed_oauth_apps/installed_oauth_apps.jsx
+++ /dev/null
@@ -1,165 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-import PropTypes from 'prop-types';
-
-import {localizeMessage} from 'utils/utils.jsx';
-import BackstageList from 'components/backstage/components/backstage_list.jsx';
-import {FormattedMessage} from 'react-intl';
-import InstalledOAuthApp from '../installed_oauth_app.jsx';
-
-export default class InstalledOAuthApps extends React.PureComponent {
- static propTypes = {
-
- /**
- * The team data
- */
- team: PropTypes.object,
-
- /**
- * The oauthApps data
- */
- oauthApps: PropTypes.object,
-
- /**
- * Set if user is admin
- */
- isSystemAdmin: PropTypes.bool,
-
- /**
- * The request state for regenOAuthAppSecret action. Contains status and error
- */
- regenOAuthAppSecretRequest: PropTypes.object.isRequired,
-
- actions: PropTypes.shape({
-
- /**
- * The function to call to fetch OAuth apps
- */
- getOAuthApps: PropTypes.func.isRequired,
-
- /**
- * The function to call when Regenerate Secret link is clicked
- */
- regenOAuthAppSecret: PropTypes.func.isRequired,
-
- /**
- * The function to call when Delete link is clicked
- */
- deleteOAuthApp: PropTypes.func.isRequired
- }).isRequired
- }
-
- constructor(props) {
- super(props);
- this.state = {
- loading: true
- };
- }
-
- componentDidMount() {
- if (window.mm_config.EnableOAuthServiceProvider === 'true') {
- this.props.actions.getOAuthApps().then(
- () => this.setState({loading: false})
- );
- }
- }
-
- deleteOAuthApp = (app) => {
- this.props.actions.deleteOAuthApp(app.id);
- }
-
- oauthAppCompare(a, b) {
- let nameA = a.name;
- if (!nameA) {
- nameA = localizeMessage('installed_integrations.unnamed_oauth_app', 'Unnamed OAuth 2.0 Application');
- }
-
- let nameB = b.name;
- if (!nameB) {
- nameB = localizeMessage('installed_integrations.unnamed_oauth_app', 'Unnamed OAuth 2.0 Application');
- }
-
- return nameA.localeCompare(nameB);
- }
-
- render() {
- const oauthApps = Object.values(this.props.oauthApps).sort(this.oauthAppCompare).map((app) => {
- return (
- <InstalledOAuthApp
- key={app.id}
- oauthApp={app}
- regenOAuthAppSecretRequest={this.props.regenOAuthAppSecretRequest}
- onRegenerateSecret={this.props.actions.regenOAuthAppSecret}
- onDelete={this.deleteOAuthApp}
- />
- );
- });
-
- const config = global.mm_config;
- const integrationsEnabled = (config.EnableOAuthServiceProvider === 'true' &&
- (this.props.isSystemAdmin || config.EnableOnlyAdminIntegrations !== 'true'));
- let props;
- if (integrationsEnabled) {
- props = {
- addLink: '/' + this.props.team.name + '/integrations/oauth2-apps/add',
- addText: localizeMessage('installed_oauth_apps.add', 'Add OAuth 2.0 Application')
- };
- }
-
- return (
- <BackstageList
- header={
- <FormattedMessage
- id='installed_oauth_apps.header'
- defaultMessage='OAuth 2.0 Applications'
- />
- }
- helpText={
- <FormattedMessage
- id='installed_oauth_apps.help'
- defaultMessage='Create {oauthApplications} to securely integrate bots and third-party apps with Mattermost. Visit the {appDirectory} to find available self-hosted apps.'
- values={{
- oauthApplications: (
- <a
- target='_blank'
- rel='noopener noreferrer'
- href='https://docs.mattermost.com/developer/oauth-2-0-applications.html'
- >
- <FormattedMessage
- id='installed_oauth_apps.help.oauthApplications'
- defaultMessage='OAuth 2.0 applications'
- />
- </a>
- ),
- appDirectory: (
- <a
- target='_blank'
- rel='noopener noreferrer'
- href='https://about.mattermost.com/default-app-directory/'
- >
- <FormattedMessage
- id='installed_oauth_apps.help.appDirectory'
- defaultMessage='App Directory'
- />
- </a>
- )
- }}
- />
- }
- emptyText={
- <FormattedMessage
- id='installed_oauth_apps.empty'
- defaultMessage='No OAuth 2.0 Applications found'
- />
- }
- searchPlaceholder={localizeMessage('installed_oauth_apps.search', 'Search OAuth 2.0 Applications')}
- loading={this.state.loading}
- {...props}
- >
- {oauthApps}
- </BackstageList>
- );
- }
-}
diff --git a/webapp/components/integrations/components/installed_outgoing_webhook.jsx b/webapp/components/integrations/components/installed_outgoing_webhook.jsx
deleted file mode 100644
index 70c606b97..000000000
--- a/webapp/components/integrations/components/installed_outgoing_webhook.jsx
+++ /dev/null
@@ -1,244 +0,0 @@
-import PropTypes from 'prop-types';
-
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import ChannelStore from 'stores/channel_store.jsx';
-
-import {FormattedMessage} from 'react-intl';
-import {Link} from 'react-router';
-
-import DeleteIntegration from './delete_integration.jsx';
-
-export default class InstalledOutgoingWebhook extends React.Component {
- static get propTypes() {
- return {
- outgoingWebhook: PropTypes.object.isRequired,
- onRegenToken: PropTypes.func.isRequired,
- onDelete: PropTypes.func.isRequired,
- filter: PropTypes.string,
- creator: PropTypes.object.isRequired,
- canChange: PropTypes.bool.isRequired,
- team: PropTypes.object.isRequired
- };
- }
-
- constructor(props) {
- super(props);
-
- this.handleRegenToken = this.handleRegenToken.bind(this);
- this.handleDelete = this.handleDelete.bind(this);
- }
-
- handleRegenToken(e) {
- e.preventDefault();
-
- this.props.onRegenToken(this.props.outgoingWebhook);
- }
-
- handleDelete() {
- this.props.onDelete(this.props.outgoingWebhook);
- }
-
- matchesFilter(outgoingWebhook, channel, filter) {
- if (!filter) {
- return true;
- }
-
- if (outgoingWebhook.display_name.toLowerCase().indexOf(filter) !== -1 ||
- outgoingWebhook.description.toLowerCase().indexOf(filter) !== -1) {
- return true;
- }
-
- for (const trigger of outgoingWebhook.trigger_words) {
- if (trigger.toLowerCase().indexOf(filter) !== -1) {
- return true;
- }
- }
-
- if (channel) {
- if (channel && channel.name.toLowerCase().indexOf(filter) !== -1) {
- return true;
- }
- }
-
- return false;
- }
-
- render() {
- const outgoingWebhook = this.props.outgoingWebhook;
- const channel = ChannelStore.get(outgoingWebhook.channel_id);
- const filter = this.props.filter ? this.props.filter.toLowerCase() : '';
- const triggerWordsFull = 0;
- const triggerWordsStartsWith = 1;
-
- if (!this.matchesFilter(outgoingWebhook, channel, filter)) {
- return null;
- }
-
- let displayName;
- if (outgoingWebhook.display_name) {
- displayName = outgoingWebhook.display_name;
- } else if (channel) {
- displayName = channel.display_name;
- } else {
- displayName = (
- <FormattedMessage
- id='installed_outgoing_webhooks.unknown_channel'
- defaultMessage='A Private Webhook'
- />
- );
- }
-
- let description = null;
- if (outgoingWebhook.description) {
- description = (
- <div className='item-details__row'>
- <span className='item-details__description'>
- {outgoingWebhook.description}
- </span>
- </div>
- );
- }
-
- let triggerWords = null;
- if (outgoingWebhook.trigger_words && outgoingWebhook.trigger_words.length > 0) {
- triggerWords = (
- <div className='item-details__row'>
- <span className='item-details__trigger-words'>
- <FormattedMessage
- id='installed_integrations.triggerWords'
- defaultMessage='Trigger Words: {triggerWords}'
- values={{
- triggerWords: outgoingWebhook.trigger_words.join(', ')
- }}
- />
- </span>
- </div>
- );
- }
-
- const urls = (
- <div className='item-details__row'>
- <span className='item-details__url'>
- <FormattedMessage
- id='installed_integrations.callback_urls'
- defaultMessage='Callback URLs: {urls}'
- values={{
- urls: outgoingWebhook.callback_urls.join(', ')
- }}
- />
- </span>
- </div>
- );
-
- let triggerWhen;
- if (outgoingWebhook.trigger_when === triggerWordsFull) {
- triggerWhen = (
- <FormattedMessage
- id='add_outgoing_webhook.triggerWordsTriggerWhenFullWord'
- defaultMessage='First word matches a trigger word exactly'
- />
- );
- } else if (outgoingWebhook.trigger_when === triggerWordsStartsWith) {
- triggerWhen = (
- <FormattedMessage
- id='add_outgoing_webhook.triggerWordsTriggerWhenStartsWith'
- defaultMessage='First word starts with a trigger word'
- />
- );
- }
-
- let actions = null;
- if (this.props.canChange) {
- actions = (
- <div className='item-actions'>
- <a
- href='#'
- onClick={this.handleRegenToken}
- >
- <FormattedMessage
- id='installed_integrations.regenToken'
- defaultMessage='Regen Token'
- />
- </a>
- {' - '}
- <Link to={`/${this.props.team.name}/integrations/outgoing_webhooks/edit?id=${outgoingWebhook.id}`}>
- <FormattedMessage
- id='installed_integrations.edit'
- defaultMessage='Edit'
- />
- </Link>
- {' - '}
- <DeleteIntegration
- messageId='installed_outgoing_webhooks.delete.confirm'
- onDelete={this.handleDelete}
- />
- </div>
- );
- }
-
- return (
- <div className='backstage-list__item'>
- <div className='item-details'>
- <div className='item-details__row'>
- <span className='item-details__name'>
- {displayName}
- </span>
- </div>
- {description}
- <div className='item-details__row'>
- <span className='item-details__content_type'>
- <FormattedMessage
- id='installed_integrations.content_type'
- defaultMessage='Content-Type: {contentType}'
- values={{
- contentType: outgoingWebhook.content_type || 'application/x-www-form-urlencoded'
- }}
- />
- </span>
- </div>
- {triggerWords}
- <div className='item-details__row'>
- <span className='item-details__trigger-when'>
- <FormattedMessage
- id='installed_integrations.triggerWhen'
- defaultMessage='Trigger When: {triggerWhen}'
- values={{
- triggerWhen
- }}
- />
- </span>
- </div>
- <div className='item-details__row'>
- <span className='item-details__token'>
- <FormattedMessage
- id='installed_integrations.token'
- defaultMessage='Token: {token}'
- values={{
- token: outgoingWebhook.token
- }}
- />
- </span>
- </div>
- <div className='item-details__row'>
- <span className='item-details__creation'>
- <FormattedMessage
- id='installed_integrations.creation'
- defaultMessage='Created by {creator} on {createAt, date, full}'
- values={{
- creator: this.props.creator.username,
- createAt: outgoingWebhook.create_at
- }}
- />
- </span>
- </div>
- {urls}
- </div>
- {actions}
- </div>
- );
- }
-}
diff --git a/webapp/components/integrations/components/installed_outgoing_webhooks.jsx b/webapp/components/integrations/components/installed_outgoing_webhooks.jsx
deleted file mode 100644
index 9b8baf3f4..000000000
--- a/webapp/components/integrations/components/installed_outgoing_webhooks.jsx
+++ /dev/null
@@ -1,182 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import BackstageList from 'components/backstage/components/backstage_list.jsx';
-import InstalledOutgoingWebhook from './installed_outgoing_webhook.jsx';
-
-import ChannelStore from 'stores/channel_store.jsx';
-import IntegrationStore from 'stores/integration_store.jsx';
-import TeamStore from 'stores/team_store.jsx';
-import UserStore from 'stores/user_store.jsx';
-
-import {loadOutgoingHooksForTeam, regenOutgoingHookToken, deleteOutgoingHook} from 'actions/integration_actions.jsx';
-
-import * as Utils from 'utils/utils.jsx';
-
-import PropTypes from 'prop-types';
-
-import React from 'react';
-import {FormattedMessage} from 'react-intl';
-
-export default class InstalledOutgoingWebhooks extends React.Component {
- static get propTypes() {
- return {
- team: PropTypes.object,
- user: PropTypes.object,
- isAdmin: PropTypes.bool
- };
- }
-
- constructor(props) {
- super(props);
-
- this.handleIntegrationChange = this.handleIntegrationChange.bind(this);
- this.handleUserChange = this.handleUserChange.bind(this);
- this.regenOutgoingWebhookToken = this.regenOutgoingWebhookToken.bind(this);
- this.deleteOutgoingWebhook = this.deleteOutgoingWebhook.bind(this);
-
- const teamId = TeamStore.getCurrentId();
-
- this.state = {
- outgoingWebhooks: IntegrationStore.getOutgoingWebhooks(teamId),
- loading: !IntegrationStore.hasReceivedOutgoingWebhooks(teamId),
- users: UserStore.getProfiles()
- };
- }
-
- componentDidMount() {
- IntegrationStore.addChangeListener(this.handleIntegrationChange);
- UserStore.addChangeListener(this.handleUserChange);
-
- if (window.mm_config.EnableOutgoingWebhooks === 'true') {
- loadOutgoingHooksForTeam(TeamStore.getCurrentId(), () => this.setState({loading: false}));
- }
- }
-
- componentWillUnmount() {
- IntegrationStore.removeChangeListener(this.handleIntegrationChange);
- UserStore.removeChangeListener(this.handleUserChange);
- }
-
- handleIntegrationChange() {
- const teamId = TeamStore.getCurrentId();
-
- this.setState({
- outgoingWebhooks: IntegrationStore.getOutgoingWebhooks(teamId)
- });
- }
-
- handleUserChange() {
- this.setState({users: UserStore.getProfiles()});
- }
-
- regenOutgoingWebhookToken(outgoingWebhook) {
- regenOutgoingHookToken(outgoingWebhook.id);
- }
-
- deleteOutgoingWebhook(outgoingWebhook) {
- deleteOutgoingHook(outgoingWebhook.id);
- }
-
- outgoingWebhookCompare(a, b) {
- let displayNameA = a.display_name;
- if (!displayNameA) {
- const channelA = ChannelStore.get(a.channel_id);
- if (channelA) {
- displayNameA = channelA.display_name;
- } else {
- displayNameA = Utils.localizeMessage('installed_outgoing_webhooks.unknown_channel', 'A Private Webhook');
- }
- }
-
- let displayNameB = b.display_name;
- if (!displayNameB) {
- const channelB = ChannelStore.get(b.channel_id);
- if (channelB) {
- displayNameB = channelB.display_name;
- } else {
- displayNameB = Utils.localizeMessage('installed_outgoing_webhooks.unknown_channel', 'A Private Webhook');
- }
- }
-
- return displayNameA.localeCompare(displayNameB);
- }
-
- render() {
- const outgoingWebhooks = this.state.outgoingWebhooks.sort(this.outgoingWebhookCompare).map((outgoingWebhook) => {
- const canChange = this.props.isAdmin || this.props.user.id === outgoingWebhook.creator_id;
-
- return (
- <InstalledOutgoingWebhook
- key={outgoingWebhook.id}
- outgoingWebhook={outgoingWebhook}
- onRegenToken={this.regenOutgoingWebhookToken}
- onDelete={this.deleteOutgoingWebhook}
- creator={this.state.users[outgoingWebhook.creator_id] || {}}
- canChange={canChange}
- team={this.props.team}
- />
- );
- });
-
- return (
- <BackstageList
- header={
- <FormattedMessage
- id='installed_outgoing_webhooks.header'
- defaultMessage='Installed Outgoing Webhooks'
- />
- }
- addText={
- <FormattedMessage
- id='installed_outgoing_webhooks.add'
- defaultMessage='Add Outgoing Webhook'
- />
- }
- addLink={'/' + this.props.team.name + '/integrations/outgoing_webhooks/add'}
- emptyText={
- <FormattedMessage
- id='installed_outgoing_webhooks.empty'
- defaultMessage='No outgoing webhooks found'
- />
- }
- helpText={
- <FormattedMessage
- id='installed_outgoing_webhooks.help'
- defaultMessage='Use outgoing webhooks to connect external tools to Mattermost. {buildYourOwn} or visit the {appDirectory} to find self-hosted, third-party apps and integrations.'
- values={{
- buildYourOwn: (
- <a
- target='_blank'
- rel='noopener noreferrer'
- href='http://docs.mattermost.com/developer/webhooks-outgoing.html'
- >
- <FormattedMessage
- id='installed_outgoing_webhooks.help.buildYourOwn'
- defaultMessage='Build your own'
- />
- </a>
- ),
- appDirectory: (
- <a
- target='_blank'
- rel='noopener noreferrer'
- href='https://about.mattermost.com/default-app-directory/'
- >
- <FormattedMessage
- id='installed_outgoing_webhooks.help.appDirectory'
- defaultMessage='App Directory'
- />
- </a>
- )
- }}
- />
- }
- searchPlaceholder={Utils.localizeMessage('installed_outgoing_webhooks.search', 'Search Outgoing Webhooks')}
- loading={this.state.loading}
- >
- {outgoingWebhooks}
- </BackstageList>
- );
- }
-}
diff --git a/webapp/components/integrations/components/integration_option.jsx b/webapp/components/integrations/components/integration_option.jsx
deleted file mode 100644
index dc411cb07..000000000
--- a/webapp/components/integrations/components/integration_option.jsx
+++ /dev/null
@@ -1,41 +0,0 @@
-import PropTypes from 'prop-types';
-
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import {Link} from 'react-router/es6';
-
-export default class IntegrationOption extends React.Component {
- static get propTypes() {
- return {
- image: PropTypes.string.isRequired,
- title: PropTypes.node.isRequired,
- description: PropTypes.node.isRequired,
- link: PropTypes.string.isRequired
- };
- }
-
- render() {
- const {image, title, description, link} = this.props;
-
- return (
- <Link
- to={link}
- className='integration-option'
- >
- <img
- className='integration-option__image'
- src={image}
- />
- <div className='integration-option__title'>
- {title}
- </div>
- <div className='integration-option__description'>
- {description}
- </div>
- </Link>
- );
- }
-}
diff --git a/webapp/components/integrations/components/integrations.jsx b/webapp/components/integrations/components/integrations.jsx
deleted file mode 100644
index 7de8810a0..000000000
--- a/webapp/components/integrations/components/integrations.jsx
+++ /dev/null
@@ -1,175 +0,0 @@
-import PropTypes from 'prop-types';
-
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-
-import {FormattedMessage} from 'react-intl';
-import IntegrationOption from './integration_option.jsx';
-
-import IncomingWebhookIcon from 'images/incoming_webhook.jpg';
-import OutgoingWebhookIcon from 'images/outgoing_webhook.jpg';
-import SlashCommandIcon from 'images/slash_command_icon.jpg';
-import OAuthIcon from 'images/oauth_icon.png';
-
-import * as Utils from 'utils/utils.jsx';
-
-export default class Integrations extends React.Component {
- static get propTypes() {
- return {
- team: PropTypes.object,
- user: PropTypes.object
- };
- }
-
- constructor(props) {
- super(props);
-
- this.updateTitle = this.updateTitle.bind(this);
- }
-
- componentDidMount() {
- this.updateTitle();
- }
-
- updateTitle() {
- let currentSiteName = '';
- if (global.window.mm_config.SiteName != null) {
- currentSiteName = global.window.mm_config.SiteName;
- }
-
- document.title = Utils.localizeMessage('admin.sidebar.integrations', 'Integrations') + ' - ' + this.props.team.display_name + ' ' + currentSiteName;
- }
-
- render() {
- const options = [];
- const config = window.mm_config;
- const isSystemAdmin = Utils.isSystemAdmin(this.props.user.roles);
-
- if (config.EnableIncomingWebhooks === 'true') {
- options.push(
- <IntegrationOption
- key='incomingWebhook'
- image={IncomingWebhookIcon}
- title={
- <FormattedMessage
- id='integrations.incomingWebhook.title'
- defaultMessage='Incoming Webhook'
- />
- }
- description={
- <FormattedMessage
- id='integrations.incomingWebhook.description'
- defaultMessage='Incoming webhooks allow external integrations to send messages'
- />
- }
- link={'/' + this.props.team.name + '/integrations/incoming_webhooks'}
- />
- );
- }
-
- if (config.EnableOutgoingWebhooks === 'true') {
- options.push(
- <IntegrationOption
- key='outgoingWebhook'
- image={OutgoingWebhookIcon}
- title={
- <FormattedMessage
- id='integrations.outgoingWebhook.title'
- defaultMessage='Outgoing Webhook'
- />
- }
- description={
- <FormattedMessage
- id='integrations.outgoingWebhook.description'
- defaultMessage='Outgoing webhooks allow external integrations to receive and respond to messages'
- />
- }
- link={'/' + this.props.team.name + '/integrations/outgoing_webhooks'}
- />
- );
- }
-
- if (config.EnableCommands === 'true') {
- options.push(
- <IntegrationOption
- key='command'
- image={SlashCommandIcon}
- title={
- <FormattedMessage
- id='integrations.command.title'
- defaultMessage='Slash Command'
- />
- }
- description={
- <FormattedMessage
- id='integrations.command.description'
- defaultMessage='Slash commands send events to an external integration'
- />
- }
- link={'/' + this.props.team.name + '/integrations/commands'}
- />
- );
- }
-
- if (config.EnableOAuthServiceProvider === 'true' && (isSystemAdmin || config.EnableOnlyAdminIntegrations !== 'true')) {
- options.push(
- <IntegrationOption
- key='oauth2Apps'
- image={OAuthIcon}
- title={
- <FormattedMessage
- id='integrations.oauthApps.title'
- defaultMessage='OAuth 2.0 Applications'
- />
- }
- description={
- <FormattedMessage
- id='integrations.oauthApps.description'
- defaultMessage='Auth 2.0 allows external applications to make authorized requests to the Mattermost API.'
- />
- }
- link={'/' + this.props.team.name + '/integrations/oauth2-apps'}
- />
- );
- }
-
- return (
- <div className='backstage-content row'>
- <div className='backstage-header'>
- <h1>
- <FormattedMessage
- id='integrations.header'
- defaultMessage='Integrations'
- />
- </h1>
- </div>
- <div className='backstage-list__help'>
- <FormattedMessage
- id='integrations.help'
- defaultMessage='Visit the {appDirectory} to find self-hosted, third-party apps and integrations for Mattermost.'
- values={{
- appDirectory: (
- <a
- target='_blank'
- rel='noopener noreferrer'
- href='https://about.mattermost.com/default-app-directory/'
- >
- <FormattedMessage
- id='integrations.help.appDirectory'
- defaultMessage='App Directory'
- />
- </a>
- )
- }}
- />
- </div>
- <div>
- {options}
- </div>
- </div>
- );
- }
-}
-