diff --git a/webapp/actions/oauth_actions.jsx b/webapp/actions/oauth_actions.jsx index d2e5b0c98b..07b4c29080 100644 --- a/webapp/actions/oauth_actions.jsx +++ b/webapp/actions/oauth_actions.jsx @@ -52,7 +52,7 @@ export function registerOAuthApp(app, onSuccess, onError) { }); if (onSuccess) { - onSuccess(); + onSuccess(data); } }, onError diff --git a/webapp/components/integrations/components/add_command.jsx b/webapp/components/integrations/components/add_command.jsx index 300e55a70b..55fe9e1217 100644 --- a/webapp/components/integrations/components/add_command.jsx +++ b/webapp/components/integrations/components/add_command.jsx @@ -160,8 +160,8 @@ export default class AddCommand extends React.Component { AsyncClient.addCommand( command, - () => { - browserHistory.push('/' + this.props.team.name + '/integrations/commands'); + (data) => { + browserHistory.push('/' + this.props.team.name + '/integrations/confirm?type=commands&id=' + data.token); }, (err) => { this.setState({ @@ -313,7 +313,7 @@ export default class AddCommand extends React.Component { /> diff --git a/webapp/components/integrations/components/add_incoming_webhook.jsx b/webapp/components/integrations/components/add_incoming_webhook.jsx index 4a3779affd..fa8a47a9c0 100644 --- a/webapp/components/integrations/components/add_incoming_webhook.jsx +++ b/webapp/components/integrations/components/add_incoming_webhook.jsx @@ -73,8 +73,8 @@ export default class AddIncomingWebhook extends React.Component { AsyncClient.addIncomingHook( hook, - () => { - browserHistory.push('/' + this.props.team.name + '/integrations/incoming_webhooks'); + (data) => { + browserHistory.push('/' + this.props.team.name + '/integrations/confirm?type=incoming_webhooks&id=' + data.id); }, (err) => { this.setState({ @@ -114,7 +114,7 @@ export default class AddIncomingWebhook extends React.Component { /> diff --git a/webapp/components/integrations/components/add_oauth_app.jsx b/webapp/components/integrations/components/add_oauth_app.jsx index 7e56aea8fc..4c01c5af00 100644 --- a/webapp/components/integrations/components/add_oauth_app.jsx +++ b/webapp/components/integrations/components/add_oauth_app.jsx @@ -144,8 +144,8 @@ export default class AddOAuthApp extends React.Component { OAuthActions.registerOAuthApp( app, - () => { - browserHistory.push('/' + this.props.team.name + '/integrations/oauth2-apps'); + (data) => { + browserHistory.push('/' + this.props.team.name + '/integrations/confirm?type=oauth2-apps&id=' + data.id); }, (err) => { this.setState({ diff --git a/webapp/components/integrations/components/add_outgoing_webhook.jsx b/webapp/components/integrations/components/add_outgoing_webhook.jsx index 540b565cd8..bf0d327ef2 100644 --- a/webapp/components/integrations/components/add_outgoing_webhook.jsx +++ b/webapp/components/integrations/components/add_outgoing_webhook.jsx @@ -119,8 +119,8 @@ export default class AddOutgoingWebhook extends React.Component { AsyncClient.addOutgoingHook( hook, - () => { - browserHistory.push('/' + this.props.team.name + '/integrations/outgoing_webhooks'); + (data) => { + browserHistory.push('/' + this.props.team.name + '/integrations/confirm?type=outgoing_webhooks&id=' + data.token); }, (err) => { this.setState({ @@ -176,6 +176,7 @@ export default class AddOutgoingWebhook extends React.Component { render() { const contentTypeOption1 = 'application/x-www-form-urlencoded'; const contentTypeOption2 = 'application/json'; + return (
@@ -186,7 +187,7 @@ export default class AddOutgoingWebhook extends React.Component { /> diff --git a/webapp/components/integrations/components/confirm_integration.jsx b/webapp/components/integrations/components/confirm_integration.jsx new file mode 100644 index 0000000000..96e24c5750 --- /dev/null +++ b/webapp/components/integrations/components/confirm_integration.jsx @@ -0,0 +1,243 @@ +// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +import React from 'react'; + +import BackstageHeader from 'components/backstage/components/backstage_header.jsx'; +import {FormattedMessage, FormattedHTMLMessage} from 'react-intl'; +import {browserHistory, Link} from 'react-router/es6'; +import SpinnerButton from 'components/spinner_button.jsx'; + +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: React.propTypes.object.isRequired, + location: React.PropTypes.object + }; + } + + constructor(props) { + super(props); + + this.handleDone = this.handleDone.bind(this); + + this.handleIntegrationChange = this.handleIntegrationChange.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); + } + + componentWillUnmount() { + IntegrationStore.removeChangeListener(this.handleIntegrationChange); + } + + handleIntegrationChange() { + const userId = UserStore.getCurrentId(); + + this.setState({ + oauthApps: IntegrationStore.getOAuthApps(userId), + loading: !IntegrationStore.hasReceivedOAuthApps(userId) + }); + } + + handleDone() { + browserHistory.push('/' + this.props.team.name + '/integrations/' + this.state.type); + this.setState({ + id: '' + }); + } + + render() { + let headerText = null; + let helpText = null; + let tokenText = null; + if (this.state.type === Constants.Integrations.COMMAND) { + headerText = ( + + ); + helpText = ( +
+ +
+ ); + tokenText = ( +
+ +
+ ); + } else if (this.state.type === Constants.Integrations.INCOMING_WEBHOOK) { + headerText = ( + + ); + helpText = ( +
+ +
+ ); + tokenText = ( +
+ +
+ ); + } else if (this.state.type === Constants.Integrations.OUTGOING_WEBHOOK) { + headerText = ( + + ); + helpText = ( +
+ +
+ ); + tokenText = ( +
+ +
+ ); + } 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 = ( + + ); + + helpText = []; + helpText.push( +
+ +
+ ); + helpText.push( +
+
+ +
+ ); + + helpText.push( +
+ +
+ ); + + tokenText = ( +
+ +
+ ); + } + } + + return ( +
+ + + {headerText} + + + + {helpText} + {tokenText} +
+ + + +
+
+ ); + } +} diff --git a/webapp/components/integrations/components/installed_incoming_webhook.jsx b/webapp/components/integrations/components/installed_incoming_webhook.jsx index 965ed2bc9a..2b514d5ec7 100644 --- a/webapp/components/integrations/components/installed_incoming_webhook.jsx +++ b/webapp/components/integrations/components/installed_incoming_webhook.jsx @@ -102,7 +102,7 @@ export default class InstalledIncomingWebhook extends React.Component { />
-
+
documentation for further details).", + "add_command.token": "Token: {token}", "add_emoji.cancel": "Cancel", "add_emoji.header": "Add", "add_emoji.image": "Image", @@ -90,7 +91,6 @@ "add_incoming_webhook.description.help": "Description for your incoming webhook.", "add_incoming_webhook.displayName": "Display Name", "add_incoming_webhook.displayName.help": "Display name for your incoming webhook made of up to 64 characters.", - "add_incoming_webhook.header": "Add", "add_incoming_webhook.name": "Name", "add_incoming_webhook.save": "Save", "add_oauth_app.callbackUrls.help": "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://.", @@ -104,6 +104,13 @@ "add_oauth_app.name.help": "Display name for your OAuth 2.0 application made of up to 64 characters.", "add_oauth_app.nameRequired": "Name for the OAuth 2.0 application is required.", "add_oauth_app.trusted.help": "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.", + "add_oauth_app.doneHelp": "Your OAuth 2.0 application has been set up. Please use the following Client ID and Client Secret when requesting authorization for your application.", + "add_oauth_app.doneUrlHelp": "Please send data to the following URL.", + "add_oauth_app.clientId": "Client ID: {id}", + "add_oauth_app.clientSecret": "Client Secret: {secret}", + "add_oauth_app.url": "URL(s): {url}", + "add_incoming_webhook.doneHelp": "Your incoming webhook has been set up. Please send data to the following URL (see documentation for further details).", + "add_incoming_webhook.url": "URL: {url}", "add_outgoing_webhook.callbackUrls": "Callback URLs (One Per Line)", "add_outgoing_webhook.callbackUrls.help": "The URL that messages will be sent to.", "add_outgoing_webhook.callbackUrlsRequired": "One or more callback URLs are required", @@ -118,9 +125,10 @@ "add_outgoing_webhook.description.help": "Description for your outgoing webhook.", "add_outgoing_webhook.displayName": "Display Name", "add_outgoing_webhook.displayName.help": "Display name for your outgoing webhook made of up to 64 characters.", - "add_outgoing_webhook.header": "Add", "add_outgoing_webhook.name": "Name", "add_outgoing_webhook.save": "Save", + "add_outgoing_webhook.doneHelp": "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 documentation for further details).", + "add_outgoing_webhook.token": "Token: {token}", "add_outgoing_webhook.triggerWords": "Trigger Words (One Per Line)", "add_outgoing_webhook.triggerWords.help": "Messages that start with one of the specified words will trigger the outgoing webhook. Optional if Channel is selected.", "add_outgoing_webhook.triggerWordsOrChannelRequired": "A valid channel or a list of trigger words is required", @@ -1187,7 +1195,7 @@ "get_team_invite_link_modal.help": "Send teammates the link below for them to sign-up to this team site. The Team Invite Link can be shared with multiple teammates as it does not change unless it's regenerated in Team Settings by a Team Admin.", "get_team_invite_link_modal.helpDisabled": "User creation has been disabled for your team. Please ask your team administrator for details.", "get_team_invite_link_modal.title": "Team Invite Link", - "installed_command.header": "Slash Commands", + "installed_commands.header": "Slash Commands", "installed_commands.add": "Add Slash Command", "installed_commands.empty": "No commands found", "installed_commands.header": "Slash Commands", @@ -1242,6 +1250,8 @@ "integrations.command.description": "Slash commands send events to external integrations", "integrations.command.title": "Slash Command", "integrations.header": "Integrations", + "integrations.done": "Done", + "integrations.add": "Add", "integrations.incomingWebhook.description": "Incoming webhooks allow external integrations to send messages", "integrations.incomingWebhook.title": "Incoming Webhook", "integrations.oauthApps.description": "OAuth 2.0 allows external applications to make authorized requests to the Mattermost API.", diff --git a/webapp/routes/route_integrations.jsx b/webapp/routes/route_integrations.jsx index a9d86a5e2a..afaf284e95 100644 --- a/webapp/routes/route_integrations.jsx +++ b/webapp/routes/route_integrations.jsx @@ -77,6 +77,12 @@ export default { } } ] + }, + { + path: 'confirm', + getComponents: (location, callback) => { + System.import('components/integrations/components/confirm_integration.jsx').then(RouteUtils.importComponentSuccess(callback)); + } } ] }; diff --git a/webapp/utils/async_client.jsx b/webapp/utils/async_client.jsx index 185fa5b4ef..674741b823 100644 --- a/webapp/utils/async_client.jsx +++ b/webapp/utils/async_client.jsx @@ -1257,7 +1257,7 @@ export function addIncomingHook(hook, success, error) { }); if (success) { - success(); + success(data); } }, (err) => { @@ -1280,7 +1280,7 @@ export function addOutgoingHook(hook, success, error) { }); if (success) { - success(); + success(data); } }, (err) => { @@ -1374,7 +1374,7 @@ export function addCommand(command, success, error) { }); if (success) { - success(); + success(data); } }, (err) => { diff --git a/webapp/utils/constants.jsx b/webapp/utils/constants.jsx index 24d1d6b19b..05068f4eaa 100644 --- a/webapp/utils/constants.jsx +++ b/webapp/utils/constants.jsx @@ -759,6 +759,12 @@ export const Constants = { NotificationPrefs: { MENTION: 'mention' }, + Integrations: { + COMMAND: 'commands', + INCOMING_WEBHOOK: 'incoming_webhooks', + OUTGOING_WEBHOOK: 'outgoing_webhooks', + OAUTH_APP: 'oauth2-apps' + }, FeatureTogglePrefix: 'feature_enabled_', PRE_RELEASE_FEATURES: { MARKDOWN_PREVIEW: {