From 5f7ab2d9a2f9ebdda35a5c687f9d4d037ec0a4ab Mon Sep 17 00:00:00 2001 From: Jonas Schwabe Date: Sun, 25 Dec 2016 16:44:44 +0100 Subject: [PATCH 01/21] Add an add team button to the TabBar --- src/browser/components/MainPage.jsx | 30 +++++++ src/browser/components/NewTeamModal.jsx | 115 ++++++++++++++++++++++++ src/browser/components/TabBar.jsx | 17 +++- src/browser/config/AppConfig.js | 12 +++ src/browser/css/index.css | 13 +++ src/browser/index.jsx | 11 +-- 6 files changed, 187 insertions(+), 11 deletions(-) create mode 100644 src/browser/components/NewTeamModal.jsx create mode 100644 src/browser/config/AppConfig.js diff --git a/src/browser/components/MainPage.jsx b/src/browser/components/MainPage.jsx index cd58cad9..83689b91 100644 --- a/src/browser/components/MainPage.jsx +++ b/src/browser/components/MainPage.jsx @@ -10,6 +10,8 @@ const MattermostView = require('./MattermostView.jsx'); const TabBar = require('./TabBar.jsx'); const HoveringURL = require('./HoveringURL.jsx'); +const NewTeamModal = require('./NewTeamModal.jsx'); + // Todo: Need to consider better way to apply styles const styles = { hoveringURL: { @@ -237,6 +239,11 @@ const MainPage = React.createClass({ this.setState({targetURL}); } }, + addTeam() { + this.setState({ + showNewTeamModal: true + }); + }, render() { var self = this; @@ -253,6 +260,7 @@ const MainPage = React.createClass({ mentionAtActiveCounts={this.state.mentionAtActiveCounts} activeKey={this.state.key} onSelect={this.handleSelect} + onAddTeam={this.addTeam} /> ); @@ -296,6 +304,25 @@ const MainPage = React.createClass({ authServerURL = `${tmpURL.protocol}//${tmpURL.host}`; authInfo = this.state.loginQueue[0].authInfo; } + var modal; + if (this.state.showNewTeamModal) { + modal = ( + { + this.setState({ + showNewTeamModal: false + }); + }} + onSave={(newTeam) => { + this.setState({ + showNewTeamModal: false + }); + this.props.teams.push(newTeam); + this.render(); + }} + /> + ); + } return (
} +
+ { modal } +
); } diff --git a/src/browser/components/NewTeamModal.jsx b/src/browser/components/NewTeamModal.jsx new file mode 100644 index 00000000..1dd9427b --- /dev/null +++ b/src/browser/components/NewTeamModal.jsx @@ -0,0 +1,115 @@ +const React = require('react'); +const {Modal, Button, FormGroup, FormControl, ControlLabel, HelpBlock} = require('react-bootstrap'); +const validUrl = require('valid-url'); + +class NewTeamModal extends React.Component { + + constructor() { + super(); + this.state = { + teamName: '', + teamUrl: '' + }; + } + + shouldComponentUpdate() { + return true; + } + + getTeamNameValidationState() { + return this.state.teamName.length > 0 ? '' : 'error'; + } + + handleTeamNameChange(e) { + this.setState({ + teamName: e.target.value + }); + } + + getTeamUrlValidationState() { + if (this.state.teamUrl.length === 0) { + return 'error'; + } + if (!validUrl.isUri(this.state.teamUrl)) { + return 'error'; + } + return ''; + } + + handleTeamUrlChange(e) { + this.setState({ + teamUrl: e.target.value + }); + } + + validateForm() { + return this.getTeamNameValidationState() === '' && + this.getTeamUrlValidationState() === ''; + } + + render() { + return ( + + + {'Add a new Team'} + + + + {'Please specify a team name and a valid Mattermost URL'} +
+ + {'Team Display Name'} + + + {'Team Name must not be empty'} + + + {'Team URL'} + + + {'Must be a valid URL'} + +
+
+ + + + + + +
+ ); + } +} + +NewTeamModal.propTypes = { + onClose: React.PropTypes.func, + onSave: React.PropTypes.func +}; + +module.exports = NewTeamModal; diff --git a/src/browser/components/TabBar.jsx b/src/browser/components/TabBar.jsx index 4282bd2e..afaf596a 100644 --- a/src/browser/components/TabBar.jsx +++ b/src/browser/components/TabBar.jsx @@ -1,5 +1,5 @@ const React = require('react'); -const {Nav, NavItem} = require('react-bootstrap'); +const {Nav, NavItem, Button} = require('react-bootstrap'); class TabBar extends React.Component { render() { @@ -75,16 +75,29 @@ class TabBar extends React.Component { onSelect={this.props.onSelect} > { tabs } + { this.renderAddTeamButton() } ); } + + renderAddTeamButton() { + return ( + + ); + } } TabBar.propTypes = { activeKey: React.PropTypes.number, id: React.PropTypes.string, onSelect: React.PropTypes.func, - teams: React.PropTypes.array + teams: React.PropTypes.array, + onAddTeam: React.PropTypes.func }; module.exports = TabBar; diff --git a/src/browser/config/AppConfig.js b/src/browser/config/AppConfig.js new file mode 100644 index 00000000..06496970 --- /dev/null +++ b/src/browser/config/AppConfig.js @@ -0,0 +1,12 @@ +const settings = require('../../common/settings'); +const {remote} = require('electron'); + +var config; +try { + const configFile = remote.app.getPath('userData') + '/config.json'; + config = settings.readFileSync(configFile); +} catch (e) { + config = {}; +} + +module.exports = config; diff --git a/src/browser/css/index.css b/src/browser/css/index.css index b0c13b5b..30e6d530 100644 --- a/src/browser/css/index.css +++ b/src/browser/css/index.css @@ -16,3 +16,16 @@ opacity: 0.01; transition: opacity 500ms ease-in-out; } + +.btn-tabButton { + margin-top: 3px; + color: #333; + background-color: #fff; + border-color: #ccc; +} + +.btn-tabButton:hover { + color: #333; + background-color: #e6e6e6; + border-color: #adadad; +} diff --git a/src/browser/index.jsx b/src/browser/index.jsx index aa236382..1c051744 100644 --- a/src/browser/index.jsx +++ b/src/browser/index.jsx @@ -9,19 +9,12 @@ const ReactDOM = require('react-dom'); const {remote, ipcRenderer} = require('electron'); const MainPage = require('./components/MainPage.jsx'); -const settings = require('../common/settings'); +const AppConfig = require('./config/AppConfig.js'); const badge = require('./js/badge'); remote.getCurrentWindow().removeAllListeners('focus'); -var config; -try { - const configFile = remote.app.getPath('userData') + '/config.json'; - config = settings.readFileSync(configFile); -} catch (e) { - window.location = 'settings.html'; -} -if (config.teams.length === 0) { +if (AppConfig.teams.length === 0) { window.location = 'settings.html'; } From aa862b293def4c8b1b5aaa510e1a5cd50038bccb Mon Sep 17 00:00:00 2001 From: Jonas Schwabe Date: Sun, 25 Dec 2016 17:03:35 +0100 Subject: [PATCH 02/21] Persist new Teams --- src/browser/components/MainPage.jsx | 4 +++- src/browser/config/AppConfig.js | 24 +++++++++++++++++------- src/browser/index.jsx | 15 ++++++++++----- 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/src/browser/components/MainPage.jsx b/src/browser/components/MainPage.jsx index 83689b91..8c4aa4bb 100644 --- a/src/browser/components/MainPage.jsx +++ b/src/browser/components/MainPage.jsx @@ -38,7 +38,8 @@ const MainPage = React.createClass({ propTypes: { disablewebsecurity: React.PropTypes.bool.isRequired, onUnreadCountChange: React.PropTypes.func.isRequired, - teams: React.PropTypes.array.isRequired + teams: React.PropTypes.array.isRequired, + onTeamConfigChange: React.PropTypes.func.isRequired }, getInitialState() { @@ -319,6 +320,7 @@ const MainPage = React.createClass({ }); this.props.teams.push(newTeam); this.render(); + this.props.onTeamConfigChange(this.props.teams); }} /> ); diff --git a/src/browser/config/AppConfig.js b/src/browser/config/AppConfig.js index 06496970..c235db5c 100644 --- a/src/browser/config/AppConfig.js +++ b/src/browser/config/AppConfig.js @@ -1,12 +1,22 @@ const settings = require('../../common/settings'); const {remote} = require('electron'); -var config; -try { - const configFile = remote.app.getPath('userData') + '/config.json'; - config = settings.readFileSync(configFile); -} catch (e) { - config = {}; +class AppConfig { + constructor(file) { + this.fileName = file; + try { + this.data = settings.readFileSync(file); + } catch (e) { + this.data = { + teams: [] + }; + } + } + + set(key, value) { + this.data[key] = value; + settings.writeFileSync(this.fileName, this.data); + } } -module.exports = config; +module.exports = new AppConfig(remote.app.getPath('userData') + '/config.json'); diff --git a/src/browser/index.jsx b/src/browser/index.jsx index 1c051744..18a7476a 100644 --- a/src/browser/index.jsx +++ b/src/browser/index.jsx @@ -14,7 +14,7 @@ const badge = require('./js/badge'); remote.getCurrentWindow().removeAllListeners('focus'); -if (AppConfig.teams.length === 0) { +if (AppConfig.data.teams.length === 0) { window.location = 'settings.html'; } @@ -33,7 +33,7 @@ function showUnreadBadgeWindows(unreadCount, mentionCount) { if (mentionCount > 0) { const dataURL = badge.createDataURL(mentionCount.toString()); sendBadge(dataURL, 'You have unread mentions (' + mentionCount + ')'); - } else if (unreadCount > 0 && config.showUnreadBadge) { + } else if (unreadCount > 0 && AppConfig.data.showUnreadBadge) { const dataURL = badge.createDataURL('•'); sendBadge(dataURL, 'You have unread channels (' + unreadCount + ')'); } else { @@ -44,7 +44,7 @@ function showUnreadBadgeWindows(unreadCount, mentionCount) { function showUnreadBadgeOSX(unreadCount, mentionCount) { if (mentionCount > 0) { remote.app.dock.setBadge(mentionCount.toString()); - } else if (unreadCount > 0 && config.showUnreadBadge) { + } else if (unreadCount > 0 && AppConfig.data.showUnreadBadge) { remote.app.dock.setBadge('•'); } else { remote.app.dock.setBadge(''); @@ -82,11 +82,16 @@ function showUnreadBadge(unreadCount, mentionCount) { } } +function teamConfigChange(teams) { + AppConfig.set('teams', teams); +} + ReactDOM.render( , document.getElementById('content') ); From 14c9112f41b237e6b36fab77dee340fb849fc1bd Mon Sep 17 00:00:00 2001 From: Jonas Schwabe Date: Sun, 25 Dec 2016 17:11:18 +0100 Subject: [PATCH 03/21] :notebook: Add Changelog entry for new 'add team' button, covers part 1,2 of #401 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 77f68acf..6e929626 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ from the final changelog of the release. Release date: TBD ### Improvements +- Added a new team button next to the team tabs #### All Platforms - Suppress white screen which is displayed for a moment on startup From 42c8f4e2edc509082fa4b134b126f5e0a17aef1d Mon Sep 17 00:00:00 2001 From: Jonas Schwabe Date: Mon, 16 Jan 2017 23:51:28 +0100 Subject: [PATCH 04/21] Use new team modal in settings view as defined in #400 --- src/browser/components/NewTeamModal.jsx | 10 +++++----- src/browser/components/SettingsPage.jsx | 2 ++ src/browser/components/TeamList.jsx | 22 ++++++++++++++-------- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/browser/components/NewTeamModal.jsx b/src/browser/components/NewTeamModal.jsx index 1dd9427b..cb442dcd 100644 --- a/src/browser/components/NewTeamModal.jsx +++ b/src/browser/components/NewTeamModal.jsx @@ -55,20 +55,20 @@ class NewTeamModal extends React.Component { - {'Please specify a team name and a valid Mattermost URL'} + {'Please specify a server name and a valid Mattermost URL'}
- {'Team Display Name'} + {'Server Display Name'} - {'Team Name must not be empty'} + {'The name of the server displayed on your desktop app tab bar.'} - {'Must be a valid URL'} + {'The URL of your Mattermost server. Must start with http:// or https://.'}
diff --git a/src/browser/components/SettingsPage.jsx b/src/browser/components/SettingsPage.jsx index c4509dfa..f4404bf9 100644 --- a/src/browser/components/SettingsPage.jsx +++ b/src/browser/components/SettingsPage.jsx @@ -159,6 +159,7 @@ const SettingsPage = React.createClass({ @@ -351,6 +352,7 @@ const SettingsPage = React.createClass({

{'⊞ Add new team'} diff --git a/src/browser/components/TeamList.jsx b/src/browser/components/TeamList.jsx index 99ff8dc4..5ddd1bf0 100644 --- a/src/browser/components/TeamList.jsx +++ b/src/browser/components/TeamList.jsx @@ -1,14 +1,15 @@ const React = require('react'); const {ListGroup} = require('react-bootstrap'); const TeamListItem = require('./TeamListItem.jsx'); -const TeamListItemNew = require('./TeamListItemNew.jsx'); +const NewTeamModal = require('./NewTeamModal.jsx'); const RemoveServerModal = require('./RemoveServerModal.jsx'); const TeamList = React.createClass({ propTypes: { onTeamsChange: React.PropTypes.func, showAddTeamForm: React.PropTypes.bool, - teams: React.PropTypes.array + teams: React.PropTypes.array, + toggleAddTeamForm: React.PropTypes.func }, getInitialState() { @@ -95,12 +96,17 @@ const TeamList = React.createClass({ var addTeamForm; if (this.props.showAddTeamForm || this.state.showTeamListItemNew) { addTeamForm = ( - { + this.setState({ + showNewTeamModal: false + }); + this.props.teams.push(newTeam); + this.render(); + + this.props.onTeamsChange(this.props.teams); + }} />); } else { addTeamForm = ''; From 8f3f59392d5321a6fbb61f0306e43b6c331f84f9 Mon Sep 17 00:00:00 2001 From: Jonas Schwabe Date: Mon, 16 Jan 2017 23:51:36 +0100 Subject: [PATCH 05/21] Add specs for new team modal --- src/browser/components/NewTeamModal.jsx | 8 ++- src/browser/components/TabBar.jsx | 1 + test/specs/browser/index_test.js | 7 ++ test/specs/browser/settings_test.js | 96 +++++++++++++++++++++++++ 4 files changed, 111 insertions(+), 1 deletion(-) diff --git a/src/browser/components/NewTeamModal.jsx b/src/browser/components/NewTeamModal.jsx index cb442dcd..10922a3c 100644 --- a/src/browser/components/NewTeamModal.jsx +++ b/src/browser/components/NewTeamModal.jsx @@ -49,7 +49,9 @@ class NewTeamModal extends React.Component { render() { return ( - + {'Add a new Team'} @@ -62,6 +64,7 @@ class NewTeamModal extends React.Component { > {'Server Display Name'} {'Team URL'} - + ); } } From be2db91d05dfb7b8dc3e464a7ddcdab4562d3a61 Mon Sep 17 00:00:00 2001 From: Jonas Schwabe Date: Sun, 22 Jan 2017 15:54:13 +0100 Subject: [PATCH 09/21] Auto focus newly created server --- src/browser/components/MainPage.jsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/browser/components/MainPage.jsx b/src/browser/components/MainPage.jsx index 8c4aa4bb..98c0ef7f 100644 --- a/src/browser/components/MainPage.jsx +++ b/src/browser/components/MainPage.jsx @@ -315,10 +315,11 @@ const MainPage = React.createClass({ }); }} onSave={(newTeam) => { - this.setState({ - showNewTeamModal: false - }); this.props.teams.push(newTeam); + this.setState({ + showNewTeamModal: false, + key: this.props.teams.length - 1 + }); this.render(); this.props.onTeamConfigChange(this.props.teams); }} From c36f7f795d3e8654f5124d389ea53cd2b7ebc575 Mon Sep 17 00:00:00 2001 From: Jonas Schwabe Date: Mon, 30 Jan 2017 20:45:47 +0100 Subject: [PATCH 10/21] Only validate new team modal input when save has been clicked --- src/browser/components/NewTeamModal.jsx | 25 ++++++++++++++++++------- test/specs/browser/settings_test.js | 9 +++++++-- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/browser/components/NewTeamModal.jsx b/src/browser/components/NewTeamModal.jsx index f1570802..96cefc98 100644 --- a/src/browser/components/NewTeamModal.jsx +++ b/src/browser/components/NewTeamModal.jsx @@ -8,11 +8,15 @@ class NewTeamModal extends React.Component { super(); this.state = { teamName: '', - teamUrl: '' + teamUrl: '', + saveStarted: false }; } getTeamNameValidationState() { + if (!this.state.saveStarted) { + return ''; + } return this.state.teamName.length > 0 ? '' : 'error'; } @@ -23,6 +27,9 @@ class NewTeamModal extends React.Component { } getTeamUrlValidationState() { + if (!this.state.saveStarted) { + return ''; + } if (this.state.teamUrl.length === 0) { return 'error'; } @@ -44,12 +51,16 @@ class NewTeamModal extends React.Component { } save() { - if (this.validateForm()) { - this.props.onSave({ - url: this.state.teamUrl, - name: this.state.teamName - }); - } + this.setState({ + saveStarted: true + }, () => { + if (this.validateForm()) { + this.props.onSave({ + url: this.state.teamUrl, + name: this.state.teamName + }); + } + }); } render() { diff --git a/test/specs/browser/settings_test.js b/test/specs/browser/settings_test.js index 58ca72dd..efc11036 100644 --- a/test/specs/browser/settings_test.js +++ b/test/specs/browser/settings_test.js @@ -266,18 +266,21 @@ describe('browser/settings.html', function desc() { it('should not be valid if no team name has been set', () => { return this.app.client. + click('#saveNewServerModal'). isExisting('.has-error #teamNameInput').should.eventually.equal(true); }); it('should not be valid if no server address has been set', () => { return this.app.client. + click('#saveNewServerModal'). isExisting('.has-error #teamUrlInput').should.eventually.equal(true); }); describe('Valid server name', () => { beforeEach(() => { return this.app.client. - setValue('#teamNameInput', 'TestTeam'); + setValue('#teamNameInput', 'TestTeam'). + click('#saveNewServerModal'); }); it('should not be marked invalid', () => { @@ -294,7 +297,8 @@ describe('browser/settings.html', function desc() { describe('Valid server url', () => { beforeEach(() => { return this.app.client. - setValue('#teamUrlInput', 'http://example.org'); + setValue('#teamUrlInput', 'http://example.org'). + click('#saveNewServerModal'); }); it('should be valid', () => { @@ -311,6 +315,7 @@ describe('browser/settings.html', function desc() { it('should not be valid if an invalid server address has been set', () => { return this.app.client. setValue('#teamUrlInput', 'superInvalid url'). + click('#saveNewServerModal'). isExisting('.has-error #teamUrlInput').should.eventually.equal(true); }); From 8db1973c9aaac0bd6ac20970cb386673b125ddd2 Mon Sep 17 00:00:00 2001 From: Jonas Schwabe Date: Mon, 30 Jan 2017 21:11:46 +0100 Subject: [PATCH 11/21] Display error message in the bottom left corner --- src/browser/components/NewTeamModal.jsx | 38 ++++++++++++++++++------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/src/browser/components/NewTeamModal.jsx b/src/browser/components/NewTeamModal.jsx index 96cefc98..669c4ada 100644 --- a/src/browser/components/NewTeamModal.jsx +++ b/src/browser/components/NewTeamModal.jsx @@ -13,11 +13,15 @@ class NewTeamModal extends React.Component { }; } - getTeamNameValidationState() { + getTeamNameValidationError() { if (!this.state.saveStarted) { - return ''; + return null; } - return this.state.teamName.length > 0 ? '' : 'error'; + return this.state.teamName.length > 0 ? null : 'Name is required.'; + } + + getTeamNameValidationState() { + return this.getTeamNameValidationError() === null ? null : 'error'; } handleTeamNameChange(e) { @@ -26,17 +30,21 @@ class NewTeamModal extends React.Component { }); } - getTeamUrlValidationState() { + getTeamUrlValidationError() { if (!this.state.saveStarted) { - return ''; + return null; } if (this.state.teamUrl.length === 0) { - return 'error'; + return 'URL is required.'; } if (!validUrl.isUri(this.state.teamUrl)) { - return 'error'; + return 'URL should start with http:// or https://.'; } - return ''; + return null; + } + + getTeamUrlValidationState() { + return this.getTeamUrlValidationError() === null ? null : 'error'; } handleTeamUrlChange(e) { @@ -45,9 +53,13 @@ class NewTeamModal extends React.Component { }); } + getError() { + return this.getTeamNameValidationError() || this.getTeamUrlValidationError(); + } + validateForm() { - return this.getTeamNameValidationState() === '' && - this.getTeamUrlValidationState() === ''; + return this.getTeamNameValidationState() === null && + this.getTeamUrlValidationState() === null; } save() { @@ -122,6 +134,12 @@ class NewTeamModal extends React.Component { +

+ {this.getError()} +
+ + >{this.getSaveButtonLabel()} @@ -170,7 +184,8 @@ class NewTeamModal extends React.Component { NewTeamModal.propTypes = { onClose: React.PropTypes.func, onSave: React.PropTypes.func, - team: React.PropTypes.object + team: React.PropTypes.object, + editMode: React.PropTypes.boolean }; module.exports = NewTeamModal; diff --git a/src/browser/components/SettingsPage.jsx b/src/browser/components/SettingsPage.jsx index 18beb8cf..4b8cc368 100644 --- a/src/browser/components/SettingsPage.jsx +++ b/src/browser/components/SettingsPage.jsx @@ -145,6 +145,11 @@ const SettingsPage = React.createClass({ showAddTeamForm: !this.state.showAddTeamForm }); }, + setShowTeamFormVisibility(val) { + this.setState({ + showAddTeamForm: val + }); + }, handleFlashWindow() { this.setState({ notifications: { @@ -182,6 +187,7 @@ const SettingsPage = React.createClass({ teams={this.state.teams} showAddTeamForm={this.state.showAddTeamForm} toggleAddTeamForm={this.toggleShowTeamForm} + setAddTeamFormVisibility={this.setShowTeamFormVisibility} onTeamsChange={this.handleTeamsChange} updateTeam={this.updateTeam} addServer={this.addServer} diff --git a/src/browser/components/TeamList.jsx b/src/browser/components/TeamList.jsx index cbf2e039..864d0964 100644 --- a/src/browser/components/TeamList.jsx +++ b/src/browser/components/TeamList.jsx @@ -11,7 +11,8 @@ const TeamList = React.createClass({ teams: React.PropTypes.array, addServer: React.PropTypes.func, updateTeam: React.PropTypes.func, - toggleAddTeamForm: React.PropTypes.func + toggleAddTeamForm: React.PropTypes.func, + setAddTeamFormVisibility: React.PropTypes.func }, getInitialState() { @@ -99,16 +100,17 @@ const TeamList = React.createClass({ if (this.props.showAddTeamForm || this.state.showEditTeamForm) { addServerForm = ( { this.setState({ - showNewTeamModal: false, + showEditTeamForm: false, team: { name: '', url: '', index: false } }); - this.props.toggleAddTeamForm(); + this.props.setAddTeamFormVisibility(false); }} onSave={(newTeam) => { var teamData = { @@ -130,8 +132,7 @@ const TeamList = React.createClass({ } }); this.render(); - - this.props.onTeamsChange(this.props.teams); + this.props.setAddTeamFormVisibility(false); }} team={this.state.team} />); From e82f0c3e6aca0672c2d5d1a8e35eb9c097637418 Mon Sep 17 00:00:00 2001 From: Jonas Schwabe Date: Fri, 3 Feb 2017 18:41:07 +0100 Subject: [PATCH 18/21] Team URL should be Server URL --- src/browser/components/NewTeamModal.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/browser/components/NewTeamModal.jsx b/src/browser/components/NewTeamModal.jsx index 87ef00a1..8ff1adcd 100644 --- a/src/browser/components/NewTeamModal.jsx +++ b/src/browser/components/NewTeamModal.jsx @@ -143,7 +143,7 @@ class NewTeamModal extends React.Component { - {'Team URL'} + {'Server URL'} Date: Fri, 3 Feb 2017 18:45:45 +0100 Subject: [PATCH 19/21] Remvoe spaceing at the bottom of new team modal --- src/browser/components/NewTeamModal.jsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/browser/components/NewTeamModal.jsx b/src/browser/components/NewTeamModal.jsx index 8ff1adcd..3d53b6ff 100644 --- a/src/browser/components/NewTeamModal.jsx +++ b/src/browser/components/NewTeamModal.jsx @@ -100,6 +100,11 @@ class NewTeamModal extends React.Component { } render() { + const noBottomSpaceing = { + 'padding-bottom': 0, + 'margin-bottom': 0 + }; + return ( {'Server URL'} - {'The URL of your Mattermost server. Must start with http:// or https://.'} + {'The URL of your Mattermost server. Must start with http:// or https://.'} From 63fe5623491cccb52eb3f4d8e5eb596978bb4b22 Mon Sep 17 00:00:00 2001 From: Jonas Schwabe Date: Fri, 3 Feb 2017 18:49:35 +0100 Subject: [PATCH 20/21] Animate NewTeamModal close --- src/browser/components/MainPage.jsx | 40 ++++++------- src/browser/components/NewTeamModal.jsx | 17 +++++- src/browser/components/TeamList.jsx | 80 ++++++++++++------------- test/specs/browser/settings_test.js | 18 +++--- 4 files changed, 81 insertions(+), 74 deletions(-) diff --git a/src/browser/components/MainPage.jsx b/src/browser/components/MainPage.jsx index 77420e54..6695c2be 100644 --- a/src/browser/components/MainPage.jsx +++ b/src/browser/components/MainPage.jsx @@ -309,27 +309,25 @@ const MainPage = React.createClass({ authServerURL = `${tmpURL.protocol}//${tmpURL.host}`; authInfo = this.state.loginQueue[0].authInfo; } - var modal; - if (this.state.showNewTeamModal) { - modal = ( - { - this.setState({ - showNewTeamModal: false - }); - }} - onSave={(newTeam) => { - this.props.teams.push(newTeam); - this.setState({ - showNewTeamModal: false, - key: this.props.teams.length - 1 - }); - this.render(); - this.props.onTeamConfigChange(this.props.teams); - }} - /> - ); - } + var modal = ( + { + this.setState({ + showNewTeamModal: false + }); + }} + onSave={(newTeam) => { + this.props.teams.push(newTeam); + this.setState({ + showNewTeamModal: false, + key: this.props.teams.length - 1 + }); + this.render(); + this.props.onTeamConfigChange(this.props.teams); + }} + /> + ); return (
{ @@ -193,7 +203,8 @@ NewTeamModal.propTypes = { onClose: React.PropTypes.func, onSave: React.PropTypes.func, team: React.PropTypes.object, - editMode: React.PropTypes.boolean + editMode: React.PropTypes.boolean, + show: React.PropTypes.boolean }; module.exports = NewTeamModal; diff --git a/src/browser/components/TeamList.jsx b/src/browser/components/TeamList.jsx index 864d0964..ddad0bb7 100644 --- a/src/browser/components/TeamList.jsx +++ b/src/browser/components/TeamList.jsx @@ -96,49 +96,45 @@ const TeamList = React.createClass({ ); }); - var addServerForm; - if (this.props.showAddTeamForm || this.state.showEditTeamForm) { - addServerForm = ( - { - this.setState({ - showEditTeamForm: false, - team: { - name: '', - url: '', - index: false - } - }); - this.props.setAddTeamFormVisibility(false); - }} - onSave={(newTeam) => { - var teamData = { - name: newTeam.name, - url: newTeam.url - }; - if (this.props.showAddTeamForm) { - this.props.addServer(teamData); - } else { - this.props.updateTeam(newTeam.index, teamData); + var addServerForm = ( + { + this.setState({ + showEditTeamForm: false, + team: { + name: '', + url: '', + index: false } - this.setState({ - showNewTeamModal: false, - showEditTeamForm: false, - team: { - name: '', - url: '', - index: false - } - }); - this.render(); - this.props.setAddTeamFormVisibility(false); - }} - team={this.state.team} - />); - } else { - addServerForm = ''; - } + }); + this.props.setAddTeamFormVisibility(false); + }} + onSave={(newTeam) => { + var teamData = { + name: newTeam.name, + url: newTeam.url + }; + if (this.props.showAddTeamForm) { + this.props.addServer(teamData); + } else { + this.props.updateTeam(newTeam.index, teamData); + } + this.setState({ + showNewTeamModal: false, + showEditTeamForm: false, + team: { + name: '', + url: '', + index: false + } + }); + this.render(); + this.props.setAddTeamFormVisibility(false); + }} + team={this.state.team} + />); const removeServer = this.props.teams[this.state.indexToRemoveServer]; const removeServerModal = ( diff --git a/test/specs/browser/settings_test.js b/test/specs/browser/settings_test.js index efc11036..f0b07406 100644 --- a/test/specs/browser/settings_test.js +++ b/test/specs/browser/settings_test.js @@ -261,6 +261,7 @@ describe('browser/settings.html', function desc() { it('should close the window after clicking cancel', () => { return this.app.client. click('#cancelNewServerModal'). + pause(1000). // Animation isExisting('#newServerModal').should.eventually.equal(false); }); @@ -334,15 +335,16 @@ describe('browser/settings.html', function desc() { it('should add the team to the config file', (done) => { this.app.client. click('#saveNewServerModal'). - click('#btnSave'); - this.app.client.pause(1000).then(() => { - const savedConfig = JSON.parse(fs.readFileSync(env.configFilePath, 'utf8')); - savedConfig.teams.should.contain({ - name: 'TestTeam', - url: 'http://example.org' + pause(1000). // Animation + click('#btnSave'). + pause(1000).then(() => { + const savedConfig = JSON.parse(fs.readFileSync(env.configFilePath, 'utf8')); + savedConfig.teams.should.contain({ + name: 'TestTeam', + url: 'http://example.org' + }); + return done(); }); - return done(); - }); }); }); }); From 9996687bfe3673245d36abbe09a862f84facb56d Mon Sep 17 00:00:00 2001 From: Jonas Schwabe Date: Fri, 3 Feb 2017 21:35:36 +0100 Subject: [PATCH 21/21] Use old url validation --- src/browser/components/NewTeamModal.jsx | 3 +-- src/package.json | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/browser/components/NewTeamModal.jsx b/src/browser/components/NewTeamModal.jsx index d74f01f8..36a852ab 100644 --- a/src/browser/components/NewTeamModal.jsx +++ b/src/browser/components/NewTeamModal.jsx @@ -1,6 +1,5 @@ const React = require('react'); const {Modal, Button, FormGroup, FormControl, ControlLabel, HelpBlock} = require('react-bootstrap'); -const validUrl = require('valid-url'); class NewTeamModal extends React.Component { constructor() { @@ -51,7 +50,7 @@ class NewTeamModal extends React.Component { if (this.state.teamUrl.length === 0) { return 'URL is required.'; } - if (!validUrl.isUri(this.state.teamUrl)) { + if (!(/^https?:\/\/.*/).test(this.state.teamUrl.trim())) { return 'URL should start with http:// or https://.'; } return null; diff --git a/src/package.json b/src/package.json index 328713a1..7ce051b6 100644 --- a/src/package.json +++ b/src/package.json @@ -24,7 +24,6 @@ "react-addons-css-transition-group": "^15.4.1", "react-bootstrap": "~0.30.7", "react-dom": "^15.4.1", - "valid-url": "^1.0.9", "yargs": "^3.32.0" } }