From ef33f3fcd1fec2b3552293f6cdb8045dcc7d214d Mon Sep 17 00:00:00 2001 From: David Lu Date: Mon, 15 Aug 2016 11:10:31 -0400 Subject: PLT-3005 Added confirmation screen to integrations (#3747) --- webapp/actions/oauth_actions.jsx | 2 +- .../integrations/components/add_command.jsx | 6 +- .../components/add_incoming_webhook.jsx | 6 +- .../integrations/components/add_oauth_app.jsx | 4 +- .../components/add_outgoing_webhook.jsx | 7 +- .../components/confirm_integration.jsx | 243 +++++++++++++++++++++ .../components/installed_incoming_webhook.jsx | 2 +- webapp/i18n/en.json | 18 +- webapp/routes/route_integrations.jsx | 6 + webapp/utils/async_client.jsx | 6 +- webapp/utils/constants.jsx | 6 + 11 files changed, 286 insertions(+), 20 deletions(-) create mode 100644 webapp/components/integrations/components/confirm_integration.jsx (limited to 'webapp') diff --git a/webapp/actions/oauth_actions.jsx b/webapp/actions/oauth_actions.jsx index d2e5b0c98..07b4c2908 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 300e55a70..55fe9e121 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 4a3779aff..fa8a47a9c 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 7e56aea8f..4c01c5af0 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 540b565cd..bf0d327ef 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 000000000..96e24c575 --- /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 965ed2bc9..2b514d5ec 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 a9d86a5e2..afaf284e9 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 185fa5b4e..674741b82 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 24d1d6b19..05068f4ea 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: { -- cgit v1.2.3-1-g7c22