From 6297922ab9561dbf774ab5d51619abfc4a411e40 Mon Sep 17 00:00:00 2001 From: Brian Olecki Date: Tue, 15 Nov 2016 10:43:16 -0500 Subject: Add support for editing slash commands (#4335) --- .../integrations/components/edit_command.jsx | 731 +++++++++++++++++++++ .../integrations/components/installed_command.jsx | 9 + 2 files changed, 740 insertions(+) create mode 100644 webapp/components/integrations/components/edit_command.jsx (limited to 'webapp/components') diff --git a/webapp/components/integrations/components/edit_command.jsx b/webapp/components/integrations/components/edit_command.jsx new file mode 100644 index 000000000..395c977ca --- /dev/null +++ b/webapp/components/integrations/components/edit_command.jsx @@ -0,0 +1,731 @@ +// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +import React from 'react'; + +import * as AsyncClient from 'utils/async_client.jsx'; +import IntegrationStore from 'stores/integration_store.jsx'; +import TeamStore from 'stores/team_store.jsx'; +import * as Utils from 'utils/utils.jsx'; + +import {loadTeamCommands} from 'actions/integration_actions.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'; +import ConfirmModal from 'components/confirm_modal.jsx'; + +const REQUEST_POST = 'P'; +const REQUEST_GET = 'G'; + +export default class EditCommand extends React.Component { + static get propTypes() { + return { + team: React.propTypes.object.isRequired, + location: React.PropTypes.object + }; + } + + constructor(props) { + super(props); + + this.handleIntegrationChange = this.handleIntegrationChange.bind(this); + + this.submitCommand = this.submitCommand.bind(this); + this.handleSubmit = this.handleSubmit.bind(this); + this.handleUpdate = this.handleUpdate.bind(this); + this.handleConfirmModal = this.handleConfirmModal.bind(this); + this.confirmModalDismissed = this.confirmModalDismissed.bind(this); + + this.updateDisplayName = this.updateDisplayName.bind(this); + this.updateDescription = this.updateDescription.bind(this); + this.updateTrigger = this.updateTrigger.bind(this); + this.updateUrl = this.updateUrl.bind(this); + this.updateMethod = this.updateMethod.bind(this); + this.updateUsername = this.updateUsername.bind(this); + this.updateIconUrl = this.updateIconUrl.bind(this); + this.updateAutocomplete = this.updateAutocomplete.bind(this); + this.updateAutocompleteHint = this.updateAutocompleteHint.bind(this); + this.updateAutocompleteDescription = this.updateAutocompleteDescription.bind(this); + + this.originalCommand = null; + this.newCommand = null; + + const teamId = TeamStore.getCurrentId(); + + this.state = { + displayName: '', + description: '', + trigger: '', + url: '', + method: REQUEST_POST, + username: '', + iconUrl: '', + autocomplete: false, + autocompleteHint: '', + autocompleteDescription: '', + saving: false, + serverError: '', + clientError: null, + showConfirmModal: false, + commands: IntegrationStore.getCommands(teamId), + loading: !IntegrationStore.hasReceivedCommands(teamId) + }; + } + + componentDidMount() { + IntegrationStore.addChangeListener(this.handleIntegrationChange); + + if (window.mm_config.EnableCommands === 'true') { + loadTeamCommands(); + } + } + + componentWillUnmount() { + IntegrationStore.removeChangeListener(this.handleIntegrationChange); + } + + handleConfirmModal() { + this.setState({showConfirmModal: true}); + } + + confirmModalDismissed() { + this.setState({showConfirmModal: false}); + } + + submitCommand() { + AsyncClient.editCommand( + this.newCmd, + browserHistory.push('/' + this.props.team.name + '/integrations/commands'), + (err) => { + this.setState({ + saving: false, + serverError: err.message + }); + } + ); + } + + handleUpdate() { + this.setState({ + saving: true, + serverError: '', + clientError: '' + }); + + this.submitCommand(); + } + + handleIntegrationChange() { + const teamId = TeamStore.getCurrentId(); + + this.setState({ + commands: IntegrationStore.getCommands(teamId), + loading: !IntegrationStore.hasReceivedCommands(teamId) + }); + + if (!this.state.loading) { + this.originalCommand = this.state.commands.filter((command) => command.id === this.props.location.query.id)[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 + }); + } + } + + 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 + }; + + 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: ( + + ) + }); + + return; + } + + if (command.trigger.indexOf('/') === 0) { + this.setState({ + saving: false, + clientError: ( + + ) + }); + + return; + } + + if (command.trigger.indexOf(' ') !== -1) { + this.setState({ + saving: false, + clientError: ( + + ) + }); + return; + } + + if (command.trigger.length < Constants.MIN_TRIGGER_LENGTH || command.trigger.length > Constants.MAX_TRIGGER_LENGTH) { + this.setState({ + saving: false, + clientError: ( + + ) + }); + + return; + } + + if (!command.url) { + this.setState({ + saving: false, + clientError: ( + + ) + }); + + return; + } + + this.newCmd = command; + + if (this.originalCommand.url !== this.newCmd.url || this.originalCommand.trigger !== this.newCmd.trigger || this.originalCommand.method !== this.newCmd.method) { + this.handleConfirmModal(); + this.setState({ + saving: false + }); + } else { + 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 = ( + + ); + + const confirmTitle = ( + + ); + + const confirmMessage = ( + + ); + + let autocompleteFields = null; + if (this.state.autocomplete) { + autocompleteFields = [( +
+ +
+ +
+ +
+
+
+ ), + ( +
+ +
+ +
+ +
+
+
+ )]; + } + + return ( +
+ + + + + + +
+
+
+ +
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+ +
+
+ + + + ) + }} + /> +
+
+
+
+ +
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ {autocompleteFields} +
+ + + + + + + + +
+
+
+
+ ); + } +} diff --git a/webapp/components/integrations/components/installed_command.jsx b/webapp/components/integrations/components/installed_command.jsx index f149a21ac..ecd7d9608 100644 --- a/webapp/components/integrations/components/installed_command.jsx +++ b/webapp/components/integrations/components/installed_command.jsx @@ -129,6 +129,15 @@ export default class InstalledCommand extends React.Component { /> {' - '} + + + + {' - '}