Divide settings.jsx into components
This commit is contained in:
400
src/browser/components/SettingsPage.jsx
Normal file
400
src/browser/components/SettingsPage.jsx
Normal file
@@ -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 = (
|
||||||
|
<Row>
|
||||||
|
<Col md={12}>
|
||||||
|
<TeamList
|
||||||
|
teams={this.state.teams}
|
||||||
|
showAddTeamForm={this.state.showAddTeamForm}
|
||||||
|
onTeamsChange={this.handleTeamsChange}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
);
|
||||||
|
|
||||||
|
var options = [];
|
||||||
|
if (process.platform === 'win32' || process.platform === 'linux') {
|
||||||
|
options.push(
|
||||||
|
<Input
|
||||||
|
key='inputHideMenuBar'
|
||||||
|
id='inputHideMenuBar'
|
||||||
|
ref='hideMenuBar'
|
||||||
|
type='checkbox'
|
||||||
|
label='Hide menu bar (Press Alt to show menu bar)'
|
||||||
|
checked={this.state.hideMenuBar}
|
||||||
|
onChange={this.handleChangeHideMenuBar}
|
||||||
|
/>);
|
||||||
|
}
|
||||||
|
if (process.platform === 'darwin' || process.platform === 'linux') {
|
||||||
|
options.push(
|
||||||
|
<Input
|
||||||
|
key='inputShowTrayIcon'
|
||||||
|
id='inputShowTrayIcon'
|
||||||
|
ref='showTrayIcon'
|
||||||
|
type='checkbox'
|
||||||
|
label={process.platform === 'darwin' ?
|
||||||
|
'Show icon on menu bar (need to restart the application)' :
|
||||||
|
'Show icon in notification area (need to restart the application)'}
|
||||||
|
checked={this.state.showTrayIcon}
|
||||||
|
onChange={this.handleChangeShowTrayIcon}
|
||||||
|
/>);
|
||||||
|
}
|
||||||
|
if (process.platform === 'linux') {
|
||||||
|
options.push(
|
||||||
|
<Input
|
||||||
|
key='inputTrayIconTheme'
|
||||||
|
ref='trayIconTheme'
|
||||||
|
type='select'
|
||||||
|
label='Icon theme (Need to restart the application)'
|
||||||
|
value={this.state.trayIconTheme}
|
||||||
|
onChange={this.handleChangeTrayIconTheme}
|
||||||
|
>
|
||||||
|
<option value='light'>{'Light'}</option>
|
||||||
|
<option value='dark'>{'Dark'}</option>
|
||||||
|
</Input>);
|
||||||
|
}
|
||||||
|
options.push(
|
||||||
|
<Input
|
||||||
|
key='inputDisableWebSecurity'
|
||||||
|
id='inputDisableWebSecurity'
|
||||||
|
ref='disablewebsecurity'
|
||||||
|
type='checkbox'
|
||||||
|
label='Allow mixed content (Enabling allows both secure and insecure content, images and scripts to render and execute. Disabling allows only secure content.)'
|
||||||
|
checked={this.state.disablewebsecurity}
|
||||||
|
onChange={this.handleChangeDisableWebSecurity}
|
||||||
|
/>);
|
||||||
|
|
||||||
|
//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(
|
||||||
|
<Input
|
||||||
|
key='inputAutoStart'
|
||||||
|
id='inputAutoStart'
|
||||||
|
ref='autostart'
|
||||||
|
type='checkbox'
|
||||||
|
label='Start app on login.'
|
||||||
|
checked={this.state.autostart}
|
||||||
|
onChange={this.handleChangeAutoStart}
|
||||||
|
/>);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.platform === 'darwin' || process.platform === 'linux') {
|
||||||
|
options.push(
|
||||||
|
<Input
|
||||||
|
key='inputMinimizeToTray'
|
||||||
|
id='inputMinimizeToTray'
|
||||||
|
ref='minimizeToTray'
|
||||||
|
type='checkbox'
|
||||||
|
label={this.state.trayWasVisible || !this.state.showTrayIcon ? 'Leave app running in notification area when the window is closed' : 'Leave app running in notification area when the window is closed (available on next restart)'}
|
||||||
|
disabled={!this.state.showTrayIcon || !this.state.trayWasVisible}
|
||||||
|
checked={this.state.minimizeToTray}
|
||||||
|
onChange={this.handleChangeMinimizeToTray}
|
||||||
|
/>);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.platform === 'win32') {
|
||||||
|
options.push(
|
||||||
|
<Input
|
||||||
|
key='inputToggleWindowOnTrayIconClick'
|
||||||
|
id='inputToggleWindowOnTrayIconClick'
|
||||||
|
ref='toggleWindowOnTrayIconClick'
|
||||||
|
type='checkbox'
|
||||||
|
label='Toggle window visibility when clicking on the tray icon.'
|
||||||
|
checked={this.state.toggleWindowOnTrayIconClick}
|
||||||
|
onChange={this.handleChangeToggleWindowOnTrayIconClick}
|
||||||
|
/>);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.platform === 'darwin' || process.platform === 'win32') {
|
||||||
|
options.push(
|
||||||
|
<Input
|
||||||
|
key='inputShowUnreadBadge'
|
||||||
|
id='inputShowUnreadBadge'
|
||||||
|
ref='showUnreadBadge'
|
||||||
|
type='checkbox'
|
||||||
|
label='Show red badge on taskbar icon to indicate unread messages. Regardless of this setting, mentions are always indicated with a red badge and item count on the taskbar icon.'
|
||||||
|
checked={this.state.showUnreadBadge}
|
||||||
|
onChange={this.handleShowUnreadBadge}
|
||||||
|
/>);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.platform === 'win32' || process.platform === 'linux') {
|
||||||
|
options.push(
|
||||||
|
<Input
|
||||||
|
key='flashWindow'
|
||||||
|
id='inputflashWindow'
|
||||||
|
ref='flashWindow'
|
||||||
|
type='checkbox'
|
||||||
|
label='Flash the taskbar icon when a new message is received.'
|
||||||
|
checked={this.state.notifications.flashWindow === 2}
|
||||||
|
onChange={this.handleFlashWindow}
|
||||||
|
/>);
|
||||||
|
}
|
||||||
|
|
||||||
|
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) ? (
|
||||||
|
<Row>
|
||||||
|
<Col md={12}>
|
||||||
|
<h2 style={settingsPage.sectionHeading}>{'App options'}</h2>
|
||||||
|
{ options }
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
) : null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Navbar
|
||||||
|
className='navbar-fixed-top'
|
||||||
|
style={settingsPage.navbar}
|
||||||
|
>
|
||||||
|
<div style={{position: 'relative'}}>
|
||||||
|
<h1 style={settingsPage.heading}>{'Settings'}</h1>
|
||||||
|
<div
|
||||||
|
style={settingsPage.close}
|
||||||
|
onClick={this.handleCancel}
|
||||||
|
>
|
||||||
|
<span>{'×'}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Navbar>
|
||||||
|
<Grid
|
||||||
|
className='settingsPage'
|
||||||
|
style={{padding: '100px 15px'}}
|
||||||
|
>
|
||||||
|
<Row>
|
||||||
|
<Col
|
||||||
|
md={10}
|
||||||
|
xs={8}
|
||||||
|
>
|
||||||
|
<h2 style={settingsPage.sectionHeading}>{'Team Management'}</h2>
|
||||||
|
</Col>
|
||||||
|
<Col
|
||||||
|
md={2}
|
||||||
|
xs={4}
|
||||||
|
>
|
||||||
|
<p className='text-right'>
|
||||||
|
<a
|
||||||
|
style={settingsPage.sectionHeadingLink}
|
||||||
|
href='#'
|
||||||
|
onClick={this.toggleShowTeamForm}
|
||||||
|
>{'⊞ Add new team'}</a>
|
||||||
|
</p>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
{ teamsRow }
|
||||||
|
<hr/>
|
||||||
|
{ optionsRow }
|
||||||
|
</Grid>
|
||||||
|
<Navbar className='navbar-fixed-bottom'>
|
||||||
|
<div
|
||||||
|
className='text-right'
|
||||||
|
style={settingsPage.footer}
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
id='btnCancel'
|
||||||
|
className='btn btn-link'
|
||||||
|
onClick={this.handleCancel}
|
||||||
|
>{'Cancel'}</button>
|
||||||
|
{ ' ' }
|
||||||
|
<button
|
||||||
|
id='btnSave'
|
||||||
|
className='btn btn-primary navbar-btn'
|
||||||
|
bsStyle='primary'
|
||||||
|
onClick={this.handleSave}
|
||||||
|
disabled={this.state.teams.length === 0}
|
||||||
|
>{'Save'}</button>
|
||||||
|
</div>
|
||||||
|
</Navbar>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = SettingsPage;
|
107
src/browser/components/TeamList.jsx
Normal file
107
src/browser/components/TeamList.jsx
Normal file
@@ -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 (
|
||||||
|
<TeamListItem
|
||||||
|
index={i}
|
||||||
|
key={'teamListItem' + i}
|
||||||
|
name={team.name}
|
||||||
|
url={team.url}
|
||||||
|
onTeamRemove={handleTeamRemove}
|
||||||
|
onTeamEditing={handleTeamEditing}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
var addTeamForm;
|
||||||
|
if (this.props.showAddTeamForm || this.state.showTeamListItemNew) {
|
||||||
|
addTeamForm = (
|
||||||
|
<TeamListItemNew
|
||||||
|
key={this.state.team.index}
|
||||||
|
onTeamAdd={this.handleTeamAdd}
|
||||||
|
teamIndex={this.state.team.index}
|
||||||
|
teamName={this.state.team.name}
|
||||||
|
teamUrl={this.state.team.url}
|
||||||
|
/>);
|
||||||
|
} else {
|
||||||
|
addTeamForm = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ListGroup class='teamList'>
|
||||||
|
{ teamNodes }
|
||||||
|
{ addTeamForm }
|
||||||
|
</ListGroup>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = TeamList;
|
47
src/browser/components/TeamListItem.jsx
Normal file
47
src/browser/components/TeamListItem.jsx
Normal file
@@ -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 (
|
||||||
|
<div className='teamListItem list-group-item'>
|
||||||
|
<div style={style.left}>
|
||||||
|
<h4 className='list-group-item-heading'>{ this.props.name }</h4>
|
||||||
|
<p className='list-group-item-text'>
|
||||||
|
{ this.props.url }
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className='pull-right'>
|
||||||
|
<a
|
||||||
|
href='#'
|
||||||
|
onClick={this.handleTeamEditing}
|
||||||
|
>{'Edit'}</a>
|
||||||
|
{' - '}
|
||||||
|
<a
|
||||||
|
href='#'
|
||||||
|
onClick={this.handleTeamRemove}
|
||||||
|
>{'Remove'}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TeamListItem.propTypes = {
|
||||||
|
name: React.PropTypes.string,
|
||||||
|
onTeamEditing: React.PropTypes.func,
|
||||||
|
onTeamRemove: React.PropTypes.func,
|
||||||
|
url: React.PropTypes.string
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = TeamListItem;
|
148
src/browser/components/TeamListItemNew.jsx
Normal file
148
src/browser/components/TeamListItemNew.jsx
Normal file
@@ -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 (
|
||||||
|
<ListGroupItem>
|
||||||
|
<form
|
||||||
|
className='form-inline'
|
||||||
|
onSubmit={this.handleSubmit}
|
||||||
|
>
|
||||||
|
<div className='form-group'>
|
||||||
|
<label htmlFor='inputTeamName'>{'Name'}</label>
|
||||||
|
{ ' ' }
|
||||||
|
<input
|
||||||
|
type='text'
|
||||||
|
required={true}
|
||||||
|
className='form-control'
|
||||||
|
id='inputTeamName'
|
||||||
|
ref='inputTeamName'
|
||||||
|
placeholder='Example team'
|
||||||
|
value={this.state.name}
|
||||||
|
onChange={this.handleNameChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{ ' ' }
|
||||||
|
<div className='form-group'>
|
||||||
|
<label htmlFor='inputTeamURL'>{'URL'}</label>
|
||||||
|
{ ' ' }
|
||||||
|
<input
|
||||||
|
type='url'
|
||||||
|
required={true}
|
||||||
|
className='form-control'
|
||||||
|
id='inputTeamURL'
|
||||||
|
ref='inputTeamURL'
|
||||||
|
placeholder='https://example.com/team'
|
||||||
|
value={this.state.url}
|
||||||
|
onChange={this.handleURLChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{ ' ' }
|
||||||
|
<Button type='submit'>
|
||||||
|
{ btnAddText }
|
||||||
|
</Button>
|
||||||
|
</form>
|
||||||
|
{ (() => {
|
||||||
|
if (this.state.errorMessage !== null) {
|
||||||
|
return (
|
||||||
|
<HelpBlock style={{color: '#777777'}}>
|
||||||
|
{ this.state.errorMessage }
|
||||||
|
</HelpBlock>);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
})() }
|
||||||
|
</ListGroupItem>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = TeamListItemNew;
|
@@ -4,666 +4,11 @@ window.eval = global.eval = () => {
|
|||||||
throw new Error('Sorry, Mattermost does not support window.eval() for security reasons.');
|
throw new Error('Sorry, Mattermost does not support window.eval() for security reasons.');
|
||||||
};
|
};
|
||||||
|
|
||||||
const {remote, ipcRenderer} = require('electron');
|
const {remote} = require('electron');
|
||||||
const settings = require('../common/settings');
|
|
||||||
|
|
||||||
const React = require('react');
|
const React = require('react');
|
||||||
const ReactDOM = require('react-dom');
|
const ReactDOM = require('react-dom');
|
||||||
const {Grid, Row, Col, Input, Button, ListGroup, ListGroupItem, HelpBlock, Navbar} = require('react-bootstrap');
|
const SettingsPage = require('./components/SettingsPage.jsx');
|
||||||
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 = (
|
|
||||||
<Row>
|
|
||||||
<Col md={12}>
|
|
||||||
<TeamList
|
|
||||||
teams={this.state.teams}
|
|
||||||
showAddTeamForm={this.state.showAddTeamForm}
|
|
||||||
onTeamsChange={this.handleTeamsChange}
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
);
|
|
||||||
|
|
||||||
var options = [];
|
|
||||||
if (process.platform === 'win32' || process.platform === 'linux') {
|
|
||||||
options.push(
|
|
||||||
<Input
|
|
||||||
key='inputHideMenuBar'
|
|
||||||
id='inputHideMenuBar'
|
|
||||||
ref='hideMenuBar'
|
|
||||||
type='checkbox'
|
|
||||||
label='Hide menu bar (Press Alt to show menu bar)'
|
|
||||||
checked={this.state.hideMenuBar}
|
|
||||||
onChange={this.handleChangeHideMenuBar}
|
|
||||||
/>);
|
|
||||||
}
|
|
||||||
if (process.platform === 'darwin' || process.platform === 'linux') {
|
|
||||||
options.push(
|
|
||||||
<Input
|
|
||||||
key='inputShowTrayIcon'
|
|
||||||
id='inputShowTrayIcon'
|
|
||||||
ref='showTrayIcon'
|
|
||||||
type='checkbox'
|
|
||||||
label={process.platform === 'darwin' ?
|
|
||||||
'Show icon on menu bar (need to restart the application)' :
|
|
||||||
'Show icon in notification area (need to restart the application)'}
|
|
||||||
checked={this.state.showTrayIcon}
|
|
||||||
onChange={this.handleChangeShowTrayIcon}
|
|
||||||
/>);
|
|
||||||
}
|
|
||||||
if (process.platform === 'linux') {
|
|
||||||
options.push(
|
|
||||||
<Input
|
|
||||||
key='inputTrayIconTheme'
|
|
||||||
ref='trayIconTheme'
|
|
||||||
type='select'
|
|
||||||
label='Icon theme (Need to restart the application)'
|
|
||||||
value={this.state.trayIconTheme}
|
|
||||||
onChange={this.handleChangeTrayIconTheme}
|
|
||||||
>
|
|
||||||
<option value='light'>{'Light'}</option>
|
|
||||||
<option value='dark'>{'Dark'}</option>
|
|
||||||
</Input>);
|
|
||||||
}
|
|
||||||
options.push(
|
|
||||||
<Input
|
|
||||||
key='inputDisableWebSecurity'
|
|
||||||
id='inputDisableWebSecurity'
|
|
||||||
ref='disablewebsecurity'
|
|
||||||
type='checkbox'
|
|
||||||
label='Allow mixed content (Enabling allows both secure and insecure content, images and scripts to render and execute. Disabling allows only secure content.)'
|
|
||||||
checked={this.state.disablewebsecurity}
|
|
||||||
onChange={this.handleChangeDisableWebSecurity}
|
|
||||||
/>);
|
|
||||||
|
|
||||||
//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(
|
|
||||||
<Input
|
|
||||||
key='inputAutoStart'
|
|
||||||
id='inputAutoStart'
|
|
||||||
ref='autostart'
|
|
||||||
type='checkbox'
|
|
||||||
label='Start app on login.'
|
|
||||||
checked={this.state.autostart}
|
|
||||||
onChange={this.handleChangeAutoStart}
|
|
||||||
/>);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (process.platform === 'darwin' || process.platform === 'linux') {
|
|
||||||
options.push(
|
|
||||||
<Input
|
|
||||||
key='inputMinimizeToTray'
|
|
||||||
id='inputMinimizeToTray'
|
|
||||||
ref='minimizeToTray'
|
|
||||||
type='checkbox'
|
|
||||||
label={this.state.trayWasVisible || !this.state.showTrayIcon ? 'Leave app running in notification area when the window is closed' : 'Leave app running in notification area when the window is closed (available on next restart)'}
|
|
||||||
disabled={!this.state.showTrayIcon || !this.state.trayWasVisible}
|
|
||||||
checked={this.state.minimizeToTray}
|
|
||||||
onChange={this.handleChangeMinimizeToTray}
|
|
||||||
/>);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (process.platform === 'win32') {
|
|
||||||
options.push(
|
|
||||||
<Input
|
|
||||||
key='inputToggleWindowOnTrayIconClick'
|
|
||||||
id='inputToggleWindowOnTrayIconClick'
|
|
||||||
ref='toggleWindowOnTrayIconClick'
|
|
||||||
type='checkbox'
|
|
||||||
label='Toggle window visibility when clicking on the tray icon.'
|
|
||||||
checked={this.state.toggleWindowOnTrayIconClick}
|
|
||||||
onChange={this.handleChangeToggleWindowOnTrayIconClick}
|
|
||||||
/>);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (process.platform === 'darwin' || process.platform === 'win32') {
|
|
||||||
options.push(
|
|
||||||
<Input
|
|
||||||
key='inputShowUnreadBadge'
|
|
||||||
id='inputShowUnreadBadge'
|
|
||||||
ref='showUnreadBadge'
|
|
||||||
type='checkbox'
|
|
||||||
label='Show red badge on taskbar icon to indicate unread messages. Regardless of this setting, mentions are always indicated with a red badge and item count on the taskbar icon.'
|
|
||||||
checked={this.state.showUnreadBadge}
|
|
||||||
onChange={this.handleShowUnreadBadge}
|
|
||||||
/>);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (process.platform === 'win32' || process.platform === 'linux') {
|
|
||||||
options.push(
|
|
||||||
<Input
|
|
||||||
key='flashWindow'
|
|
||||||
id='inputflashWindow'
|
|
||||||
ref='flashWindow'
|
|
||||||
type='checkbox'
|
|
||||||
label='Flash the taskbar icon when a new message is received.'
|
|
||||||
checked={this.state.notifications.flashWindow === 2}
|
|
||||||
onChange={this.handleFlashWindow}
|
|
||||||
/>);
|
|
||||||
}
|
|
||||||
|
|
||||||
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) ? (
|
|
||||||
<Row>
|
|
||||||
<Col md={12}>
|
|
||||||
<h2 style={settingsPage.sectionHeading}>{'App options'}</h2>
|
|
||||||
{ options }
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
) : null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Navbar
|
|
||||||
className='navbar-fixed-top'
|
|
||||||
style={settingsPage.navbar}
|
|
||||||
>
|
|
||||||
<div style={{position: 'relative'}}>
|
|
||||||
<h1 style={settingsPage.heading}>{'Settings'}</h1>
|
|
||||||
<div
|
|
||||||
style={settingsPage.close}
|
|
||||||
onClick={this.handleCancel}
|
|
||||||
>
|
|
||||||
<span>{'×'}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Navbar>
|
|
||||||
<Grid
|
|
||||||
className='settingsPage'
|
|
||||||
style={{padding: '100px 15px'}}
|
|
||||||
>
|
|
||||||
<Row>
|
|
||||||
<Col
|
|
||||||
md={10}
|
|
||||||
xs={8}
|
|
||||||
>
|
|
||||||
<h2 style={settingsPage.sectionHeading}>{'Team Management'}</h2>
|
|
||||||
</Col>
|
|
||||||
<Col
|
|
||||||
md={2}
|
|
||||||
xs={4}
|
|
||||||
>
|
|
||||||
<p className='text-right'>
|
|
||||||
<a
|
|
||||||
style={settingsPage.sectionHeadingLink}
|
|
||||||
href='#'
|
|
||||||
onClick={this.toggleShowTeamForm}
|
|
||||||
>{'⊞ Add new team'}</a>
|
|
||||||
</p>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
{ teamsRow }
|
|
||||||
<hr/>
|
|
||||||
{ optionsRow }
|
|
||||||
</Grid>
|
|
||||||
<Navbar className='navbar-fixed-bottom'>
|
|
||||||
<div
|
|
||||||
className='text-right'
|
|
||||||
style={settingsPage.footer}
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
id='btnCancel'
|
|
||||||
className='btn btn-link'
|
|
||||||
onClick={this.handleCancel}
|
|
||||||
>{'Cancel'}</button>
|
|
||||||
{ ' ' }
|
|
||||||
<button
|
|
||||||
id='btnSave'
|
|
||||||
className='btn btn-primary navbar-btn'
|
|
||||||
bsStyle='primary'
|
|
||||||
onClick={this.handleSave}
|
|
||||||
disabled={this.state.teams.length === 0}
|
|
||||||
>{'Save'}</button>
|
|
||||||
</div>
|
|
||||||
</Navbar>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
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 (
|
|
||||||
<TeamListItem
|
|
||||||
index={i}
|
|
||||||
key={'teamListItem' + i}
|
|
||||||
name={team.name}
|
|
||||||
url={team.url}
|
|
||||||
onTeamRemove={handleTeamRemove}
|
|
||||||
onTeamEditing={handleTeamEditing}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
var addTeamForm;
|
|
||||||
if (this.props.showAddTeamForm || this.state.showTeamListItemNew) {
|
|
||||||
addTeamForm = (
|
|
||||||
<TeamListItemNew
|
|
||||||
key={this.state.team.index}
|
|
||||||
onTeamAdd={this.handleTeamAdd}
|
|
||||||
teamIndex={this.state.team.index}
|
|
||||||
teamName={this.state.team.name}
|
|
||||||
teamUrl={this.state.team.url}
|
|
||||||
/>);
|
|
||||||
} else {
|
|
||||||
addTeamForm = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ListGroup class='teamList'>
|
|
||||||
{ teamNodes }
|
|
||||||
{ addTeamForm }
|
|
||||||
</ListGroup>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var TeamListItem = React.createClass({
|
|
||||||
handleTeamRemove() {
|
|
||||||
this.props.onTeamRemove();
|
|
||||||
},
|
|
||||||
handleTeamEditing() {
|
|
||||||
this.props.onTeamEditing();
|
|
||||||
},
|
|
||||||
render() {
|
|
||||||
var style = {
|
|
||||||
left: {
|
|
||||||
display: 'inline-block'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<div className='teamListItem list-group-item'>
|
|
||||||
<div style={style.left}>
|
|
||||||
<h4 className='list-group-item-heading'>{ this.props.name }</h4>
|
|
||||||
<p className='list-group-item-text'>
|
|
||||||
{ this.props.url }
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div className='pull-right'>
|
|
||||||
<a
|
|
||||||
href='#'
|
|
||||||
onClick={this.handleTeamEditing}
|
|
||||||
>{'Edit'}</a>
|
|
||||||
{' - '}
|
|
||||||
<a
|
|
||||||
href='#'
|
|
||||||
onClick={this.handleTeamRemove}
|
|
||||||
>{'Remove'}</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
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 (
|
|
||||||
<ListGroupItem>
|
|
||||||
<form
|
|
||||||
className='form-inline'
|
|
||||||
onSubmit={this.handleSubmit}
|
|
||||||
>
|
|
||||||
<div className='form-group'>
|
|
||||||
<label htmlFor='inputTeamName'>{'Name'}</label>
|
|
||||||
{ ' ' }
|
|
||||||
<input
|
|
||||||
type='text'
|
|
||||||
required
|
|
||||||
className='form-control'
|
|
||||||
id='inputTeamName'
|
|
||||||
ref='inputTeamName'
|
|
||||||
placeholder='Example team'
|
|
||||||
value={this.state.name}
|
|
||||||
onChange={this.handleNameChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{ ' ' }
|
|
||||||
<div className='form-group'>
|
|
||||||
<label htmlFor='inputTeamURL'>{'URL'}</label>
|
|
||||||
{ ' ' }
|
|
||||||
<input
|
|
||||||
type='url'
|
|
||||||
required
|
|
||||||
className='form-control'
|
|
||||||
id='inputTeamURL'
|
|
||||||
ref='inputTeamURL'
|
|
||||||
placeholder='https://example.com/team'
|
|
||||||
value={this.state.url}
|
|
||||||
onChange={this.handleURLChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{ ' ' }
|
|
||||||
<Button type='submit'>
|
|
||||||
{ btnAddText }
|
|
||||||
</Button>
|
|
||||||
</form>
|
|
||||||
{ (() => {
|
|
||||||
if (this.state.errorMessage !== null) {
|
|
||||||
return (
|
|
||||||
<HelpBlock style={{color: '#777777'}}>
|
|
||||||
{ this.state.errorMessage }
|
|
||||||
</HelpBlock>);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
})() }
|
|
||||||
</ListGroupItem>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var configFile = remote.getGlobal('config-file');
|
var configFile = remote.getGlobal('config-file');
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user