From 4df36a504cebc61fa1e5e6f7980f9245b475facf Mon Sep 17 00:00:00 2001 From: Chris Date: Fri, 23 Jun 2017 15:47:24 -0700 Subject: [PATCH] PLT-6714: add /settings command (#6716) * add /settings command * update receiver name --- api/command_settings_test.go | 13 ++++++ app/command_settings.go | 42 +++++++++++++++++++ i18n/en.json | 12 ++++++ webapp/actions/channel_actions.jsx | 20 +++++++-- webapp/actions/global_actions.jsx | 7 ++++ webapp/components/needs_team/needs_team.jsx | 2 + webapp/components/sidebar_header_dropdown.jsx | 28 +++---------- webapp/components/sidebar_right_menu.jsx | 8 +--- .../user_settings/user_settings_modal.jsx | 37 ++++++++++++---- webapp/stores/modal_store.jsx | 1 + webapp/utils/constants.jsx | 1 + 11 files changed, 131 insertions(+), 40 deletions(-) create mode 100644 api/command_settings_test.go create mode 100644 app/command_settings.go diff --git a/api/command_settings_test.go b/api/command_settings_test.go new file mode 100644 index 0000000000..f34154f39c --- /dev/null +++ b/api/command_settings_test.go @@ -0,0 +1,13 @@ +// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package api + +import ( + "testing" +) + +func TestSettingsCommand(t *testing.T) { + th := Setup().InitBasic() + th.BasicClient.Must(th.BasicClient.Command(th.BasicChannel.Id, "/settings")) +} diff --git a/app/command_settings.go b/app/command_settings.go new file mode 100644 index 0000000000..e84492cc29 --- /dev/null +++ b/app/command_settings.go @@ -0,0 +1,42 @@ +// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package app + +import ( + "github.com/mattermost/platform/model" + goi18n "github.com/nicksnyder/go-i18n/i18n" +) + +type SettingsProvider struct { +} + +const ( + CMD_SETTINGS = "settings" +) + +func init() { + RegisterCommandProvider(&SettingsProvider{}) +} + +func (settings *SettingsProvider) GetTrigger() string { + return CMD_SETTINGS +} + +func (settings *SettingsProvider) GetCommand(T goi18n.TranslateFunc) *model.Command { + return &model.Command{ + Trigger: CMD_SETTINGS, + AutoComplete: true, + AutoCompleteDesc: T("api.command_settings.desc"), + AutoCompleteHint: "", + DisplayName: T("api.command_settings.name"), + } +} + +func (settings *SettingsProvider) DoCommand(args *model.CommandArgs, message string) *model.CommandResponse { + // This command is handled client-side and shouldn't hit the server. + return &model.CommandResponse{ + Text: args.T("api.command_settings.unsupported.app_error"), + ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL, + } +} diff --git a/i18n/en.json b/i18n/en.json index 584c8dec61..b2e0b7b5c9 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -659,6 +659,18 @@ "id": "api.command_online.success", "translation": "You are now online" }, + { + "id": "api.command_settings.desc", + "translation": "Open the Account Settings dialog" + }, + { + "id": "api.command_settings.name", + "translation": "settings" + }, + { + "id": "api.command_settings.unsupported.app_error", + "translation": "The settings command is not supported on your device" + }, { "id": "api.command_shortcuts.browser.channel_next", "translation": "{{.ChannelNextCmd}}: Next channel in your history\n" diff --git a/webapp/actions/channel_actions.jsx b/webapp/actions/channel_actions.jsx index e756275bc5..3a01c40899 100644 --- a/webapp/actions/channel_actions.jsx +++ b/webapp/actions/channel_actions.jsx @@ -9,6 +9,8 @@ import ChannelStore from 'stores/channel_store.jsx'; import * as ChannelUtils from 'utils/channel_utils.jsx'; import PreferenceStore from 'stores/preference_store.jsx'; +import * as GlobalActions from 'actions/global_actions.jsx'; + import {loadProfilesForSidebar, loadNewDMIfNeeded, loadNewGMIfNeeded} from 'actions/user_actions.jsx'; import {trackEvent} from 'actions/diagnostics_actions.jsx'; @@ -66,9 +68,15 @@ export function goToChannel(channel) { export function executeCommand(message, args, success, error) { let msg = message; - msg = msg.substring(0, msg.indexOf(' ')).toLowerCase() + msg.substring(msg.indexOf(' '), msg.length); + let cmdLength = msg.indexOf(' '); + if (cmdLength < 0) { + cmdLength = msg.length; + } + const cmd = msg.substring(0, cmdLength).toLowerCase(); + msg = cmd + msg.substring(cmdLength, msg.length); - if (message.indexOf('/shortcuts') !== -1) { + switch (cmd) { + case '/shortcuts': if (UserAgent.isMobile()) { const err = {message: Utils.localizeMessage('create_post.shortcutsNotSupported', 'Keyboard shortcuts are not supported on your device')}; error(err); @@ -78,7 +86,12 @@ export function executeCommand(message, args, success, error) { } else if (message.indexOf('mac') !== -1) { msg = '/shortcuts'; } + break; + case '/settings': + GlobalActions.showAccountSettingsModal(); + return; } + Client.executeCommand(msg, args, success, (err) => { AsyncClient.dispatchError(err, 'executeCommand'); @@ -86,7 +99,8 @@ export function executeCommand(message, args, success, error) { if (error) { error(err); } - }); + } + ); } export function setChannelAsRead(channelIdParam) { diff --git a/webapp/actions/global_actions.jsx b/webapp/actions/global_actions.jsx index ca38ec9f1c..d3fa80d312 100644 --- a/webapp/actions/global_actions.jsx +++ b/webapp/actions/global_actions.jsx @@ -197,6 +197,13 @@ export function emitUserCommentedEvent(post) { }); } +export function showAccountSettingsModal() { + AppDispatcher.handleViewAction({ + type: ActionTypes.TOGGLE_ACCOUNT_SETTINGS_MODAL, + value: true + }); +} + export function showDeletePostModal(post, commentCount = 0) { AppDispatcher.handleViewAction({ type: ActionTypes.TOGGLE_DELETE_POST_MODAL, diff --git a/webapp/components/needs_team/needs_team.jsx b/webapp/components/needs_team/needs_team.jsx index 6fd2d32088..e86e4fb113 100644 --- a/webapp/components/needs_team/needs_team.jsx +++ b/webapp/components/needs_team/needs_team.jsx @@ -33,6 +33,7 @@ import store from 'stores/redux_store.jsx'; import {getPost} from 'mattermost-redux/selectors/entities/posts'; // Modals +import UserSettingsModal from 'components/user_settings/user_settings_modal.jsx'; import GetPostLinkModal from 'components/get_post_link_modal.jsx'; import GetPublicLinkModal from 'components/get_public_link_modal.jsx'; import GetTeamInviteLinkModal from 'components/get_team_invite_link_modal.jsx'; @@ -218,6 +219,7 @@ export default class NeedsTeam extends React.Component { {content} + diff --git a/webapp/components/sidebar_header_dropdown.jsx b/webapp/components/sidebar_header_dropdown.jsx index 5a7784733d..54f8c3a2d1 100644 --- a/webapp/components/sidebar_header_dropdown.jsx +++ b/webapp/components/sidebar_header_dropdown.jsx @@ -13,7 +13,6 @@ import WebrtcStore from 'stores/webrtc_store.jsx'; import AboutBuildModal from './about_build_modal.jsx'; import SidebarHeaderDropdownButton from './sidebar_header_dropdown_button.jsx'; import TeamMembersModal from './team_members_modal.jsx'; -import UserSettingsModal from './user_settings/user_settings_modal.jsx'; import AddUsersToTeam from 'components/add_users_to_team'; import {Constants, WebrtcActionTypes} from 'utils/constants.jsx'; @@ -45,7 +44,7 @@ export default class SidebarHeaderDropdown extends React.Component { this.handleAboutModal = this.handleAboutModal.bind(this); this.aboutModalDismissed = this.aboutModalDismissed.bind(this); - this.toggleAccountSettingsModal = this.toggleAccountSettingsModal.bind(this); + this.showAccountSettingsModal = this.showAccountSettingsModal.bind(this); this.showAddUsersToTeamModal = this.showAddUsersToTeamModal.bind(this); this.hideAddUsersToTeamModal = this.hideAddUsersToTeamModal.bind(this); this.showInviteMemberModal = this.showInviteMemberModal.bind(this); @@ -54,7 +53,6 @@ export default class SidebarHeaderDropdown extends React.Component { this.hideTeamMembersModal = this.hideTeamMembersModal.bind(this); this.onTeamChange = this.onTeamChange.bind(this); - this.openAccountSettings = this.openAccountSettings.bind(this); this.renderCustomEmojiLink = this.renderCustomEmojiLink.bind(this); @@ -66,7 +64,6 @@ export default class SidebarHeaderDropdown extends React.Component { showAboutModal: false, showDropdown: false, showTeamMembersModal: false, - showUserSettingsModal: false, showAddUsersToTeamModal: false }; } @@ -104,13 +101,12 @@ export default class SidebarHeaderDropdown extends React.Component { this.setState({showAboutModal: false}); } - toggleAccountSettingsModal(e) { + showAccountSettingsModal(e) { e.preventDefault(); - this.setState({ - showUserSettingsModal: !this.state.showUserSettingsModal, - showDropdown: false - }); + this.setState({showDropdown: false}); + + GlobalActions.showAccountSettingsModal(); } showAddUsersToTeamModal(e) { @@ -160,7 +156,6 @@ export default class SidebarHeaderDropdown extends React.Component { componentDidMount() { TeamStore.addChangeListener(this.onTeamChange); - document.addEventListener('keydown', this.openAccountSettings); } onTeamChange() { @@ -174,13 +169,6 @@ export default class SidebarHeaderDropdown extends React.Component { componentWillUnmount() { $(ReactDOM.findDOMNode(this.refs.dropdown)).off('hide.bs.dropdown'); TeamStore.removeChangeListener(this.onTeamChange); - document.removeEventListener('keydown', this.openAccountSettings); - } - - openAccountSettings(e) { - if (Utils.cmdOrCtrlPressed(e) && e.shiftKey && e.keyCode === Constants.KeyCodes.A) { - this.toggleAccountSettingsModal(e); - } } renderCustomEmojiLink() { @@ -527,7 +515,7 @@ export default class SidebarHeaderDropdown extends React.Component { this.setState({showUserSettingsModal: false})} - /> {teamMembersModal} this.setState({showUserSettingsModal: true})} + onClick={() => GlobalActions.showAccountSettingsModal()} > - this.setState({showUserSettingsModal: false})} - />