diff --git a/src/browser/components/SettingsPage.jsx b/src/browser/components/SettingsPage.jsx new file mode 100644 index 00000000..488115b0 --- /dev/null +++ b/src/browser/components/SettingsPage.jsx @@ -0,0 +1,400 @@ +const React = require('react'); +const {Col, Grid, Navbar, Input, Row} = require('react-bootstrap'); + +const {ipcRenderer, remote} = require('electron'); +const AutoLaunch = require('auto-launch'); + +const settings = require('../../common/settings'); + +const TeamList = require('./TeamList.jsx'); + +const appLauncher = new AutoLaunch({ + name: 'Mattermost', + isHidden: true +}); + +function backToIndex() { + remote.getCurrentWindow().loadURL('file://' + __dirname + '/index.html'); +} + +const SettingsPage = React.createClass({ + propTypes: { + configFile: React.PropTypes.string + }, + + getInitialState() { + var initialState; + try { + initialState = settings.readFileSync(this.props.configFile); + } catch (e) { + initialState = settings.loadDefault(); + } + + initialState.showAddTeamForm = false; + initialState.trayWasVisible = remote.getCurrentWindow().trayWasVisible; + + return initialState; + }, + componentDidMount() { + if (process.platform === 'win32' || process.platform === 'linux') { + var self = this; + appLauncher.isEnabled().then((enabled) => { + self.setState({ + autostart: enabled + }); + }); + } + }, + handleTeamsChange(teams) { + this.setState({ + showAddTeamForm: false, + teams + }); + }, + handleSave() { + var config = { + teams: this.state.teams, + hideMenuBar: this.state.hideMenuBar, + showTrayIcon: this.state.showTrayIcon, + trayIconTheme: this.state.trayIconTheme, + disablewebsecurity: this.state.disablewebsecurity, + version: settings.version, + minimizeToTray: this.state.minimizeToTray, + toggleWindowOnTrayIconClick: this.state.toggleWindowOnTrayIconClick, + notifications: { + flashWindow: this.state.notifications.flashWindow + }, + showUnreadBadge: this.state.showUnreadBadge + }; + settings.writeFileSync(this.props.configFile, config); + if (process.platform === 'win32' || process.platform === 'linux') { + var currentWindow = remote.getCurrentWindow(); + currentWindow.setAutoHideMenuBar(config.hideMenuBar); + currentWindow.setMenuBarVisibility(!config.hideMenuBar); + + var autostart = this.state.autostart; + appLauncher.isEnabled().then((enabled) => { + if (enabled && !autostart) { + appLauncher.disable(); + } else if (!enabled && autostart) { + appLauncher.enable(); + } + }); + } + + ipcRenderer.send('update-menu', config); + ipcRenderer.send('update-config'); + + backToIndex(); + }, + handleCancel() { + backToIndex(); + }, + handleChangeDisableWebSecurity() { + this.setState({ + disablewebsecurity: this.refs.disablewebsecurity.getChecked() + }); + }, + handleChangeHideMenuBar() { + this.setState({ + hideMenuBar: this.refs.hideMenuBar.getChecked() + }); + }, + handleChangeShowTrayIcon() { + var shouldShowTrayIcon = this.refs.showTrayIcon.getChecked(); + this.setState({ + showTrayIcon: shouldShowTrayIcon + }); + + if (process.platform === 'darwin' && !shouldShowTrayIcon) { + this.setState({ + minimizeToTray: false + }); + } + }, + handleChangeTrayIconTheme() { + this.setState({ + trayIconTheme: this.refs.trayIconTheme.getValue() + }); + }, + handleChangeAutoStart() { + this.setState({ + autostart: this.refs.autostart.getChecked() + }); + }, + handleChangeMinimizeToTray() { + var shouldMinimizeToTray = + (process.platform !== 'darwin' || this.refs.showTrayIcon.getChecked()) && + this.refs.minimizeToTray.getChecked(); + + this.setState({ + minimizeToTray: shouldMinimizeToTray + }); + }, + handleChangeToggleWindowOnTrayIconClick() { + this.setState({ + toggleWindowOnTrayIconClick: this.refs.toggleWindowOnTrayIconClick.getChecked() + }); + }, + toggleShowTeamForm() { + this.setState({ + showAddTeamForm: !this.state.showAddTeamForm + }); + }, + handleFlashWindow() { + this.setState({ + notifications: { + flashWindow: this.refs.flashWindow.getChecked() ? 2 : 0 + } + }); + }, + handleShowUnreadBadge() { + this.setState({ + showUnreadBadge: this.refs.showUnreadBadge.getChecked() + }); + }, + render() { + var teamsRow = ( + + + + + + ); + + var options = []; + if (process.platform === 'win32' || process.platform === 'linux') { + options.push( + ); + } + if (process.platform === 'darwin' || process.platform === 'linux') { + options.push( + ); + } + if (process.platform === 'linux') { + options.push( + + + + ); + } + options.push( + ); + + //OSX has an option in the Dock, to set the app to autostart, so we choose to not support this option for OSX + if (process.platform === 'win32' || process.platform === 'linux') { + options.push( + ); + } + + if (process.platform === 'darwin' || process.platform === 'linux') { + options.push( + ); + } + + if (process.platform === 'win32') { + options.push( + ); + } + + if (process.platform === 'darwin' || process.platform === 'win32') { + options.push( + ); + } + + if (process.platform === 'win32' || process.platform === 'linux') { + options.push( + ); + } + + const settingsPage = { + navbar: { + backgroundColor: '#fff' + }, + close: { + position: 'absolute', + right: '0', + top: '10px', + fontSize: '35px', + fontWeight: 'normal', + color: '#bbb', + cursor: 'pointer' + }, + heading: { + textAlign: 'center', + fontSize: '24px', + margin: '0', + padding: '1em 0' + }, + sectionHeading: { + fontSize: '20px', + margin: '0', + padding: '1em 0' + }, + sectionHeadingLink: { + marginTop: '24px', + display: 'inline-block', + fontSize: '15px' + }, + footer: { + padding: '0.4em 0' + } + }; + + var optionsRow = (options.length > 0) ? ( + + +

{'App options'}

+ { options } + +
+ ) : null; + + return ( +
+ +
+

{'Settings'}

+
+ {'×'} +
+
+
+ + + +

{'Team Management'}

+ + +

+ {'⊞ Add new team'} +

+ +
+ { teamsRow } +
+ { optionsRow } +
+ +
+ + { ' ' } + +
+
+
+ ); + } +}); + +module.exports = SettingsPage; diff --git a/src/browser/components/TeamList.jsx b/src/browser/components/TeamList.jsx new file mode 100644 index 00000000..1fb40451 --- /dev/null +++ b/src/browser/components/TeamList.jsx @@ -0,0 +1,107 @@ +const React = require('react'); +const {ListGroup} = require('react-bootstrap'); +const TeamListItem = require('./TeamListItem.jsx'); +const TeamListItemNew = require('./TeamListItemNew.jsx'); + +const TeamList = React.createClass({ + propTypes: { + onTeamsChange: React.PropTypes.func, + showAddTeamForm: React.PropTypes.bool, + teams: React.PropTypes.array + }, + + getInitialState() { + return { + showTeamListItemNew: false, + team: { + url: '', + name: '', + index: false + } + }; + }, + handleTeamRemove(index) { + console.log(index); + var teams = this.props.teams; + teams.splice(index, 1); + this.props.onTeamsChange(teams); + }, + handleTeamAdd(team) { + var teams = this.props.teams; + + // check if team already exists and then change existing team or add new one + if ((typeof team.index !== 'undefined') && teams[team.index]) { + teams[team.index].name = team.name; + teams[team.index].url = team.url; + } else { + teams.push(team); + } + + this.setState({ + showTeamListItemNew: false, + team: { + url: '', + name: '', + index: false + } + }); + + this.props.onTeamsChange(teams); + }, + handleTeamEditing(teamName, teamUrl, teamIndex) { + this.setState({ + showTeamListItemNew: true, + team: { + url: teamUrl, + name: teamName, + index: teamIndex + } + }); + }, + render() { + var self = this; + var teamNodes = this.props.teams.map((team, i) => { + function handleTeamRemove() { + self.handleTeamRemove(i); + } + + function handleTeamEditing() { + self.handleTeamEditing(team.name, team.url, i); + } + + return ( + + ); + }); + + var addTeamForm; + if (this.props.showAddTeamForm || this.state.showTeamListItemNew) { + addTeamForm = ( + ); + } else { + addTeamForm = ''; + } + + return ( + + { teamNodes } + { addTeamForm } + + ); + } +}); + +module.exports = TeamList; diff --git a/src/browser/components/TeamListItem.jsx b/src/browser/components/TeamListItem.jsx new file mode 100644 index 00000000..aefefca8 --- /dev/null +++ b/src/browser/components/TeamListItem.jsx @@ -0,0 +1,47 @@ +const React = require('react'); + +class TeamListItem extends React.Component { + handleTeamRemove() { + this.props.onTeamRemove(); + } + handleTeamEditing() { + this.props.onTeamEditing(); + } + render() { + var style = { + left: { + display: 'inline-block' + } + }; + return ( +
+
+

{ this.props.name }

+

+ { this.props.url } +

+
+
+ {'Edit'} + {' - '} + {'Remove'} +
+
+ ); + } +} + +TeamListItem.propTypes = { + name: React.PropTypes.string, + onTeamEditing: React.PropTypes.func, + onTeamRemove: React.PropTypes.func, + url: React.PropTypes.string +}; + +module.exports = TeamListItem; diff --git a/src/browser/components/TeamListItemNew.jsx b/src/browser/components/TeamListItemNew.jsx new file mode 100644 index 00000000..07ed8b23 --- /dev/null +++ b/src/browser/components/TeamListItemNew.jsx @@ -0,0 +1,148 @@ +const React = require('react'); +const {findDOMNode} = require('react-dom'); +const {Button, HelpBlock, ListGroupItem} = require('react-bootstrap'); + +const TeamListItemNew = React.createClass({ + propTypes: { + onTeamAdd: React.PropTypes.func, + teamIndex: React.PropTypes.number, + teamName: React.PropTypes.string, + teamUrl: React.PropTypes.string + }, + + getInitialState() { + return { + name: this.props.teamName, + url: this.props.teamUrl, + index: this.props.teamIndex, + errorMessage: null + }; + }, + handleSubmit(e) { + console.log('submit'); + e.preventDefault(); + const errorMessage = this.getValidationErrorMessage(); + if (errorMessage) { + this.setState({ + errorMessage + }); + return; + } + + this.props.onTeamAdd({ + name: this.state.name.trim(), + url: this.state.url.trim(), + index: this.state.index + }); + + this.setState({ + name: '', + url: '', + index: '', + errorMessage: null + }); + }, + handleNameChange(e) { + console.log('name'); + this.setState({ + name: e.target.value + }); + }, + handleURLChange(e) { + console.log('url'); + this.setState({ + url: e.target.value + }); + }, + + getValidationErrorMessage() { + if (this.state.name.trim() === '') { + return 'Name is required.'; + } else if (this.state.url.trim() === '') { + return 'URL is required.'; + } else if (!(/^https?:\/\/.*/).test(this.state.url.trim())) { + return 'URL should start with http:// or https://.'; + } + return null; + }, + + componentDidMount() { + const inputTeamName = findDOMNode(this.refs.inputTeamName); + const setErrorMessage = () => { + this.setState({ + errorMessage: this.getValidationErrorMessage() + }); + }; + inputTeamName.addEventListener('invalid', setErrorMessage); + const inputTeamURL = findDOMNode(this.refs.inputTeamURL); + inputTeamURL.addEventListener('invalid', setErrorMessage); + }, + + render() { + var existingTeam = false; + if (this.state.name !== '' && this.state.url !== '') { + existingTeam = true; + } + + var btnAddText; + if (existingTeam) { + btnAddText = 'Save'; + } else { + btnAddText = 'Add'; + } + + return ( + +
+
+ + { ' ' } + +
+ { ' ' } +
+ + { ' ' } + +
+ { ' ' } + +
+ { (() => { + if (this.state.errorMessage !== null) { + return ( + + { this.state.errorMessage } + ); + } + return null; + })() } +
+ ); + } +}); + +module.exports = TeamListItemNew; diff --git a/src/browser/settings.jsx b/src/browser/settings.jsx index 8e11e663..8fa6f24d 100644 --- a/src/browser/settings.jsx +++ b/src/browser/settings.jsx @@ -4,666 +4,11 @@ window.eval = global.eval = () => { throw new Error('Sorry, Mattermost does not support window.eval() for security reasons.'); }; -const {remote, ipcRenderer} = require('electron'); -const settings = require('../common/settings'); +const {remote} = require('electron'); const React = require('react'); const ReactDOM = require('react-dom'); -const {Grid, Row, Col, Input, Button, ListGroup, ListGroupItem, HelpBlock, Navbar} = require('react-bootstrap'); -var AutoLaunch = require('auto-launch'); - -var appLauncher = new AutoLaunch({ - name: 'Mattermost', - isHidden: true -}); - -function backToIndex() { - remote.getCurrentWindow().loadURL('file://' + __dirname + '/index.html'); -} - -var SettingsPage = React.createClass({ - getInitialState() { - var initialState; - try { - initialState = settings.readFileSync(this.props.configFile); - } catch (e) { - initialState = settings.loadDefault(); - } - - initialState.showAddTeamForm = false; - initialState.trayWasVisible = remote.getCurrentWindow().trayWasVisible; - - return initialState; - }, - componentDidMount() { - if (process.platform === 'win32' || process.platform === 'linux') { - var self = this; - appLauncher.isEnabled().then((enabled) => { - self.setState({ - autostart: enabled - }); - }); - } - }, - handleTeamsChange(teams) { - this.setState({ - showAddTeamForm: false, - teams - }); - }, - handleSave() { - var config = { - teams: this.state.teams, - hideMenuBar: this.state.hideMenuBar, - showTrayIcon: this.state.showTrayIcon, - trayIconTheme: this.state.trayIconTheme, - disablewebsecurity: this.state.disablewebsecurity, - version: settings.version, - minimizeToTray: this.state.minimizeToTray, - toggleWindowOnTrayIconClick: this.state.toggleWindowOnTrayIconClick, - notifications: { - flashWindow: this.state.notifications.flashWindow - }, - showUnreadBadge: this.state.showUnreadBadge - }; - settings.writeFileSync(this.props.configFile, config); - if (process.platform === 'win32' || process.platform === 'linux') { - var currentWindow = remote.getCurrentWindow(); - currentWindow.setAutoHideMenuBar(config.hideMenuBar); - currentWindow.setMenuBarVisibility(!config.hideMenuBar); - - var autostart = this.state.autostart; - appLauncher.isEnabled().then((enabled) => { - if (enabled && !autostart) { - appLauncher.disable(); - } else if (!enabled && autostart) { - appLauncher.enable(); - } - }); - } - - ipcRenderer.send('update-menu', config); - ipcRenderer.send('update-config'); - - backToIndex(); - }, - handleCancel() { - backToIndex(); - }, - handleChangeDisableWebSecurity() { - this.setState({ - disablewebsecurity: this.refs.disablewebsecurity.getChecked() - }); - }, - handleChangeHideMenuBar() { - this.setState({ - hideMenuBar: this.refs.hideMenuBar.getChecked() - }); - }, - handleChangeShowTrayIcon() { - var shouldShowTrayIcon = this.refs.showTrayIcon.getChecked(); - this.setState({ - showTrayIcon: shouldShowTrayIcon - }); - - if (process.platform === 'darwin' && !shouldShowTrayIcon) { - this.setState({ - minimizeToTray: false - }); - } - }, - handleChangeTrayIconTheme() { - this.setState({ - trayIconTheme: this.refs.trayIconTheme.getValue() - }); - }, - handleChangeAutoStart() { - this.setState({ - autostart: this.refs.autostart.getChecked() - }); - }, - handleChangeMinimizeToTray() { - var shouldMinimizeToTray = - (process.platform !== 'darwin' || this.refs.showTrayIcon.getChecked()) && - this.refs.minimizeToTray.getChecked(); - - this.setState({ - minimizeToTray: shouldMinimizeToTray - }); - }, - handleChangeToggleWindowOnTrayIconClick() { - this.setState({ - toggleWindowOnTrayIconClick: this.refs.toggleWindowOnTrayIconClick.getChecked() - }); - }, - toggleShowTeamForm() { - this.setState({ - showAddTeamForm: !this.state.showAddTeamForm - }); - }, - handleFlashWindow() { - this.setState({ - notifications: { - flashWindow: this.refs.flashWindow.getChecked() ? 2 : 0 - } - }); - }, - handleShowUnreadBadge() { - this.setState({ - showUnreadBadge: this.refs.showUnreadBadge.getChecked() - }); - }, - render() { - var teamsRow = ( - - - - - - ); - - var options = []; - if (process.platform === 'win32' || process.platform === 'linux') { - options.push( - ); - } - if (process.platform === 'darwin' || process.platform === 'linux') { - options.push( - ); - } - if (process.platform === 'linux') { - options.push( - - - - ); - } - options.push( - ); - - //OSX has an option in the Dock, to set the app to autostart, so we choose to not support this option for OSX - if (process.platform === 'win32' || process.platform === 'linux') { - options.push( - ); - } - - if (process.platform === 'darwin' || process.platform === 'linux') { - options.push( - ); - } - - if (process.platform === 'win32') { - options.push( - ); - } - - if (process.platform === 'darwin' || process.platform === 'win32') { - options.push( - ); - } - - if (process.platform === 'win32' || process.platform === 'linux') { - options.push( - ); - } - - const settingsPage = { - navbar: { - backgroundColor: '#fff' - }, - close: { - position: 'absolute', - right: '0', - top: '10px', - fontSize: '35px', - fontWeight: 'normal', - color: '#bbb', - cursor: 'pointer' - }, - heading: { - textAlign: 'center', - fontSize: '24px', - margin: '0', - padding: '1em 0' - }, - sectionHeading: { - fontSize: '20px', - margin: '0', - padding: '1em 0' - }, - sectionHeadingLink: { - marginTop: '24px', - display: 'inline-block', - fontSize: '15px' - }, - footer: { - padding: '0.4em 0' - } - }; - - var optionsRow = (options.length > 0) ? ( - - -

{'App options'}

- { options } - -
- ) : null; - - return ( -
- -
-

{'Settings'}

-
- {'×'} -
-
-
- - - -

{'Team Management'}

- - -

- {'⊞ Add new team'} -

- -
- { teamsRow } -
- { optionsRow } -
- -
- - { ' ' } - -
-
-
- ); - } -}); - -var TeamList = React.createClass({ - getInitialState() { - return { - showTeamListItemNew: false, - team: { - url: '', - name: '', - index: false - } - }; - }, - handleTeamRemove(index) { - console.log(index); - var teams = this.props.teams; - teams.splice(index, 1); - this.props.onTeamsChange(teams); - }, - handleTeamAdd(team) { - var teams = this.props.teams; - - // check if team already exists and then change existing team or add new one - if ((typeof team.index !== 'undefined') && teams[team.index]) { - teams[team.index].name = team.name; - teams[team.index].url = team.url; - } else { - teams.push(team); - } - - this.setState({ - showTeamListItemNew: false, - team: { - url: '', - name: '', - index: false - } - }); - - this.props.onTeamsChange(teams); - }, - handleTeamEditing(teamName, teamUrl, teamIndex) { - this.setState({ - showTeamListItemNew: true, - team: { - url: teamUrl, - name: teamName, - index: teamIndex - } - }); - }, - render() { - var self = this; - var teamNodes = this.props.teams.map((team, i) => { - function handleTeamRemove() { - self.handleTeamRemove(i); - } - - function handleTeamEditing() { - self.handleTeamEditing(team.name, team.url, i); - } - - return ( - - ); - }); - - var addTeamForm; - if (this.props.showAddTeamForm || this.state.showTeamListItemNew) { - addTeamForm = ( - ); - } else { - addTeamForm = ''; - } - - return ( - - { teamNodes } - { addTeamForm } - - ); - } -}); - -var TeamListItem = React.createClass({ - handleTeamRemove() { - this.props.onTeamRemove(); - }, - handleTeamEditing() { - this.props.onTeamEditing(); - }, - render() { - var style = { - left: { - display: 'inline-block' - } - }; - return ( -
-
-

{ this.props.name }

-

- { this.props.url } -

-
-
- {'Edit'} - {' - '} - {'Remove'} -
-
- ); - } -}); - -var TeamListItemNew = React.createClass({ - getInitialState() { - return { - name: this.props.teamName, - url: this.props.teamUrl, - index: this.props.teamIndex, - errorMessage: null - }; - }, - handleSubmit(e) { - console.log('submit'); - e.preventDefault(); - const errorMessage = this.getValidationErrorMessage(); - if (errorMessage) { - this.setState({ - errorMessage - }); - return; - } - - this.props.onTeamAdd({ - name: this.state.name.trim(), - url: this.state.url.trim(), - index: this.state.index - }); - - this.setState({ - name: '', - url: '', - index: '', - errorMessage: null - }); - }, - handleNameChange(e) { - console.log('name'); - this.setState({ - name: e.target.value - }); - }, - handleURLChange(e) { - console.log('url'); - this.setState({ - url: e.target.value - }); - }, - - getValidationErrorMessage() { - if (this.state.name.trim() === '') { - return 'Name is required.'; - } else if (this.state.url.trim() === '') { - return 'URL is required.'; - } else if (!(/^https?:\/\/.*/).test(this.state.url.trim())) { - return 'URL should start with http:// or https://.'; - } - return null; - }, - - componentDidMount() { - const inputTeamName = ReactDOM.findDOMNode(this.refs.inputTeamName); - const setErrorMessage = () => { - this.setState({ - errorMessage: this.getValidationErrorMessage() - }); - }; - inputTeamName.addEventListener('invalid', setErrorMessage); - const inputTeamURL = ReactDOM.findDOMNode(this.refs.inputTeamURL); - inputTeamURL.addEventListener('invalid', setErrorMessage); - }, - - render() { - var existingTeam = false; - if (this.state.name !== '' && this.state.url !== '') { - existingTeam = true; - } - - var btnAddText; - if (existingTeam) { - btnAddText = 'Save'; - } else { - btnAddText = 'Add'; - } - - return ( - -
-
- - { ' ' } - -
- { ' ' } -
- - { ' ' } - -
- { ' ' } - -
- { (() => { - if (this.state.errorMessage !== null) { - return ( - - { this.state.errorMessage } - ); - } - return null; - })() } -
- ); - } -}); +const SettingsPage = require('./components/SettingsPage.jsx'); var configFile = remote.getGlobal('config-file');