Implement auto-saving

This commit is contained in:
Yuya Ochiai
2017-02-15 22:07:10 +09:00
parent 90623bcf84
commit 3447d49cbd
4 changed files with 125 additions and 29 deletions

View 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;

View File

@@ -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>
);
}

View File

@@ -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%;
}

View File

@@ -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"
}
}