Implement auto-saving
This commit is contained in:
33
src/browser/components/AutoSaveIndicator.jsx
Normal file
33
src/browser/components/AutoSaveIndicator.jsx
Normal file
@@ -0,0 +1,33 @@
|
||||
const React = require('react');
|
||||
const {Alert} = require('react-bootstrap');
|
||||
|
||||
function AutoSaveIndicator(props) {
|
||||
const {savingState, errorMessage, ...rest} = props;
|
||||
return (
|
||||
<Alert
|
||||
className='AutoSaveIndicator'
|
||||
{...rest}
|
||||
bsStyle={props.savingState === 'error' ? 'danger' : 'info'}
|
||||
>
|
||||
{(() => {
|
||||
switch (props.savingState) {
|
||||
case 'saving':
|
||||
return 'Saving...';
|
||||
case 'saved':
|
||||
return 'Saved!';
|
||||
case 'error':
|
||||
return props.errorMessage;
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
})()}
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
|
||||
AutoSaveIndicator.propTypes = {
|
||||
savingState: React.PropTypes.string.isRequired,
|
||||
errorMessage: React.PropTypes.string
|
||||
};
|
||||
|
||||
module.exports = AutoSaveIndicator;
|
@@ -1,13 +1,16 @@
|
||||
const React = require('react');
|
||||
const ReactDOM = require('react-dom');
|
||||
const ReactCSSTransitionGroup = require('react-addons-css-transition-group');
|
||||
const {Button, Checkbox, Col, FormGroup, Grid, HelpBlock, Navbar, Radio, Row} = require('react-bootstrap');
|
||||
|
||||
const {ipcRenderer, remote} = require('electron');
|
||||
const AutoLaunch = require('auto-launch');
|
||||
const {debounce} = require('underscore');
|
||||
|
||||
const settings = require('../../common/settings');
|
||||
|
||||
const TeamList = require('./TeamList.jsx');
|
||||
const AutoSaveIndicator = require('./AutoSaveIndicator.jsx');
|
||||
|
||||
const appLauncher = new AutoLaunch({
|
||||
name: 'Mattermost',
|
||||
@@ -38,6 +41,7 @@ const SettingsPage = React.createClass({
|
||||
if (initialState.teams.length === 0) {
|
||||
initialState.showAddTeamForm = true;
|
||||
}
|
||||
initialState.savingState = 'done';
|
||||
|
||||
return initialState;
|
||||
},
|
||||
@@ -56,6 +60,19 @@ const SettingsPage = React.createClass({
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
setSavingState(state) {
|
||||
if (!this.setSavingStateDone) {
|
||||
this.setSavingStateDone = debounce(() => {
|
||||
this.setState({savingState: 'done'});
|
||||
}, 2000);
|
||||
}
|
||||
this.setState({savingState: state});
|
||||
if (state === 'saved') {
|
||||
this.setSavingStateDone();
|
||||
}
|
||||
},
|
||||
|
||||
handleTeamsChange(teams) {
|
||||
this.setState({
|
||||
showAddTeamForm: false,
|
||||
@@ -64,8 +81,10 @@ const SettingsPage = React.createClass({
|
||||
if (teams.length === 0) {
|
||||
this.setState({showAddTeamForm: true});
|
||||
}
|
||||
setImmediate(this.saveConfig);
|
||||
},
|
||||
handleSave(index) {
|
||||
saveConfig() {
|
||||
this.setSavingState('saving');
|
||||
var config = {
|
||||
teams: this.state.teams,
|
||||
showTrayIcon: this.state.showTrayIcon,
|
||||
@@ -83,28 +102,38 @@ const SettingsPage = React.createClass({
|
||||
var autostart = this.state.autostart;
|
||||
appLauncher.isEnabled().then((enabled) => {
|
||||
if (enabled && !autostart) {
|
||||
appLauncher.disable();
|
||||
appLauncher.disable().then(() => {
|
||||
this.setSavingState('saved');
|
||||
});
|
||||
} else if (!enabled && autostart) {
|
||||
appLauncher.enable();
|
||||
appLauncher.enable().then(() => {
|
||||
this.setSavingState('saved');
|
||||
});
|
||||
} else {
|
||||
this.setSavingState('saved');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.setSavingState('saved');
|
||||
}
|
||||
|
||||
ipcRenderer.send('update-menu', config);
|
||||
ipcRenderer.send('update-config');
|
||||
|
||||
backToIndex(index);
|
||||
},
|
||||
handleCancel() {
|
||||
backToIndex();
|
||||
},
|
||||
backToIndexWithSave(index) {
|
||||
this.handleSave(index);
|
||||
},
|
||||
handleChangeDisableWebSecurity() {
|
||||
this.setState({
|
||||
disablewebsecurity: this.refs.disablewebsecurity.props.checked
|
||||
});
|
||||
setImmediate(this.saveConfig);
|
||||
},
|
||||
handleChangeHideMenuBar() {
|
||||
this.setState({
|
||||
hideMenuBar: this.refs.hideMenuBar.props.checked
|
||||
});
|
||||
setImmediate(this.saveConfig);
|
||||
},
|
||||
handleChangeShowTrayIcon() {
|
||||
var shouldShowTrayIcon = !this.refs.showTrayIcon.props.checked;
|
||||
@@ -117,16 +146,20 @@ const SettingsPage = React.createClass({
|
||||
minimizeToTray: false
|
||||
});
|
||||
}
|
||||
|
||||
setImmediate(this.saveConfig);
|
||||
},
|
||||
handleChangeTrayIconTheme() {
|
||||
this.setState({
|
||||
trayIconTheme: ReactDOM.findDOMNode(this.refs.trayIconTheme).value
|
||||
});
|
||||
setImmediate(this.saveConfig);
|
||||
},
|
||||
handleChangeAutoStart() {
|
||||
this.setState({
|
||||
autostart: !this.refs.autostart.props.checked
|
||||
});
|
||||
setImmediate(this.saveConfig);
|
||||
},
|
||||
handleChangeMinimizeToTray() {
|
||||
const shouldMinimizeToTray = this.state.showTrayIcon && !this.refs.minimizeToTray.props.checked;
|
||||
@@ -134,16 +167,19 @@ const SettingsPage = React.createClass({
|
||||
this.setState({
|
||||
minimizeToTray: shouldMinimizeToTray
|
||||
});
|
||||
setImmediate(this.saveConfig);
|
||||
},
|
||||
toggleShowTeamForm() {
|
||||
this.setState({
|
||||
showAddTeamForm: !this.state.showAddTeamForm
|
||||
});
|
||||
setImmediate(this.saveConfig);
|
||||
},
|
||||
setShowTeamFormVisibility(val) {
|
||||
this.setState({
|
||||
showAddTeamForm: val
|
||||
});
|
||||
setImmediate(this.saveConfig);
|
||||
},
|
||||
handleFlashWindow() {
|
||||
this.setState({
|
||||
@@ -151,11 +187,13 @@ const SettingsPage = React.createClass({
|
||||
flashWindow: this.refs.flashWindow.props.checked ? 0 : 2
|
||||
}
|
||||
});
|
||||
setImmediate(this.saveConfig);
|
||||
},
|
||||
handleShowUnreadBadge() {
|
||||
this.setState({
|
||||
showUnreadBadge: !this.refs.showUnreadBadge.props.checked
|
||||
});
|
||||
setImmediate(this.saveConfig);
|
||||
},
|
||||
|
||||
updateTeam(index, newData) {
|
||||
@@ -164,6 +202,7 @@ const SettingsPage = React.createClass({
|
||||
this.setState({
|
||||
teams
|
||||
});
|
||||
setImmediate(this.saveConfig);
|
||||
},
|
||||
|
||||
addServer(team) {
|
||||
@@ -172,6 +211,7 @@ const SettingsPage = React.createClass({
|
||||
this.setState({
|
||||
teams
|
||||
});
|
||||
setImmediate(this.saveConfig);
|
||||
},
|
||||
|
||||
render() {
|
||||
@@ -186,7 +226,7 @@ const SettingsPage = React.createClass({
|
||||
onTeamsChange={this.handleTeamsChange}
|
||||
updateTeam={this.updateTeam}
|
||||
addServer={this.addServer}
|
||||
onTeamClick={this.backToIndexWithSave}
|
||||
onTeamClick={backToIndex}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
@@ -388,7 +428,7 @@ const SettingsPage = React.createClass({
|
||||
</Navbar>
|
||||
<Grid
|
||||
className='settingsPage'
|
||||
style={{padding: '100px 15px'}}
|
||||
style={{paddingTop: '100px'}}
|
||||
>
|
||||
<Row>
|
||||
<Col
|
||||
@@ -415,26 +455,15 @@ const SettingsPage = React.createClass({
|
||||
<hr/>
|
||||
{ optionsRow }
|
||||
</Grid>
|
||||
<Navbar className='navbar-fixed-bottom'>
|
||||
<div
|
||||
className='text-right'
|
||||
style={settingsPage.footer}
|
||||
<div className='IndicatorContainer'>
|
||||
<ReactCSSTransitionGroup
|
||||
transitionName='AutoSaveIndicator'
|
||||
transitionEnterTimeout={500}
|
||||
transitionLeaveTimeout={1000}
|
||||
>
|
||||
<Button
|
||||
id='btnCancel'
|
||||
className='btn-link'
|
||||
onClick={this.handleCancel}
|
||||
>{'Cancel'}</Button>
|
||||
{ ' ' }
|
||||
<Button
|
||||
id='btnSave'
|
||||
className='navbar-btn'
|
||||
bsStyle='primary'
|
||||
onClick={this.handleSave}
|
||||
disabled={this.state.teams.length === 0}
|
||||
>{'Save'}</Button>
|
||||
</div>
|
||||
</Navbar>
|
||||
{ this.state.savingState === 'done' ? null : <AutoSaveIndicator savingState={this.state.savingState}/> }
|
||||
</ReactCSSTransitionGroup>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@@ -3,6 +3,39 @@
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
.IndicatorContainer {
|
||||
pointer-events: none;
|
||||
position: fixed;
|
||||
top: 100px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.IndicatorContainer * {
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.AutoSaveIndicator-enter {
|
||||
opacity: 0.01;
|
||||
}
|
||||
|
||||
.AutoSaveIndicator-enter.AutoSaveIndicator-enter-active {
|
||||
opacity: 1;
|
||||
transition: opacity 0ms;
|
||||
}
|
||||
|
||||
.AutoSaveIndicator-leave {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.AutoSaveIndicator-leave.AutoSaveIndicator-leave-active {
|
||||
opacity: 0.01;
|
||||
transition: opacity 1s cubic-bezier(0.19, 1, 0.22, 1);
|
||||
}
|
||||
|
||||
.checkbox > label {
|
||||
width: 100%;
|
||||
}
|
||||
|
@@ -24,6 +24,7 @@
|
||||
"react-addons-css-transition-group": "^15.4.1",
|
||||
"react-bootstrap": "~0.30.7",
|
||||
"react-dom": "^15.4.1",
|
||||
"underscore": "^1.8.3",
|
||||
"yargs": "^3.32.0"
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user