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 }
+
+
+
+
+ );
+ }
+}
+
+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 }
-
-
-
-
- );
- }
-});
-
-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');