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 React = require('react');
|
||||||
const ReactDOM = require('react-dom');
|
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 {Button, Checkbox, Col, FormGroup, Grid, HelpBlock, Navbar, Radio, Row} = require('react-bootstrap');
|
||||||
|
|
||||||
const {ipcRenderer, remote} = require('electron');
|
const {ipcRenderer, remote} = require('electron');
|
||||||
const AutoLaunch = require('auto-launch');
|
const AutoLaunch = require('auto-launch');
|
||||||
|
const {debounce} = require('underscore');
|
||||||
|
|
||||||
const settings = require('../../common/settings');
|
const settings = require('../../common/settings');
|
||||||
|
|
||||||
const TeamList = require('./TeamList.jsx');
|
const TeamList = require('./TeamList.jsx');
|
||||||
|
const AutoSaveIndicator = require('./AutoSaveIndicator.jsx');
|
||||||
|
|
||||||
const appLauncher = new AutoLaunch({
|
const appLauncher = new AutoLaunch({
|
||||||
name: 'Mattermost',
|
name: 'Mattermost',
|
||||||
@@ -38,6 +41,7 @@ const SettingsPage = React.createClass({
|
|||||||
if (initialState.teams.length === 0) {
|
if (initialState.teams.length === 0) {
|
||||||
initialState.showAddTeamForm = true;
|
initialState.showAddTeamForm = true;
|
||||||
}
|
}
|
||||||
|
initialState.savingState = 'done';
|
||||||
|
|
||||||
return initialState;
|
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) {
|
handleTeamsChange(teams) {
|
||||||
this.setState({
|
this.setState({
|
||||||
showAddTeamForm: false,
|
showAddTeamForm: false,
|
||||||
@@ -64,8 +81,10 @@ const SettingsPage = React.createClass({
|
|||||||
if (teams.length === 0) {
|
if (teams.length === 0) {
|
||||||
this.setState({showAddTeamForm: true});
|
this.setState({showAddTeamForm: true});
|
||||||
}
|
}
|
||||||
|
setImmediate(this.saveConfig);
|
||||||
},
|
},
|
||||||
handleSave(index) {
|
saveConfig() {
|
||||||
|
this.setSavingState('saving');
|
||||||
var config = {
|
var config = {
|
||||||
teams: this.state.teams,
|
teams: this.state.teams,
|
||||||
showTrayIcon: this.state.showTrayIcon,
|
showTrayIcon: this.state.showTrayIcon,
|
||||||
@@ -83,28 +102,38 @@ const SettingsPage = React.createClass({
|
|||||||
var autostart = this.state.autostart;
|
var autostart = this.state.autostart;
|
||||||
appLauncher.isEnabled().then((enabled) => {
|
appLauncher.isEnabled().then((enabled) => {
|
||||||
if (enabled && !autostart) {
|
if (enabled && !autostart) {
|
||||||
appLauncher.disable();
|
appLauncher.disable().then(() => {
|
||||||
|
this.setSavingState('saved');
|
||||||
|
});
|
||||||
} else if (!enabled && autostart) {
|
} 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-menu', config);
|
||||||
ipcRenderer.send('update-config');
|
ipcRenderer.send('update-config');
|
||||||
|
|
||||||
backToIndex(index);
|
|
||||||
},
|
},
|
||||||
handleCancel() {
|
handleCancel() {
|
||||||
backToIndex();
|
backToIndex();
|
||||||
},
|
},
|
||||||
backToIndexWithSave(index) {
|
|
||||||
this.handleSave(index);
|
|
||||||
},
|
|
||||||
handleChangeDisableWebSecurity() {
|
handleChangeDisableWebSecurity() {
|
||||||
this.setState({
|
this.setState({
|
||||||
disablewebsecurity: this.refs.disablewebsecurity.props.checked
|
disablewebsecurity: this.refs.disablewebsecurity.props.checked
|
||||||
});
|
});
|
||||||
|
setImmediate(this.saveConfig);
|
||||||
|
},
|
||||||
|
handleChangeHideMenuBar() {
|
||||||
|
this.setState({
|
||||||
|
hideMenuBar: this.refs.hideMenuBar.props.checked
|
||||||
|
});
|
||||||
|
setImmediate(this.saveConfig);
|
||||||
},
|
},
|
||||||
handleChangeShowTrayIcon() {
|
handleChangeShowTrayIcon() {
|
||||||
var shouldShowTrayIcon = !this.refs.showTrayIcon.props.checked;
|
var shouldShowTrayIcon = !this.refs.showTrayIcon.props.checked;
|
||||||
@@ -117,16 +146,20 @@ const SettingsPage = React.createClass({
|
|||||||
minimizeToTray: false
|
minimizeToTray: false
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setImmediate(this.saveConfig);
|
||||||
},
|
},
|
||||||
handleChangeTrayIconTheme() {
|
handleChangeTrayIconTheme() {
|
||||||
this.setState({
|
this.setState({
|
||||||
trayIconTheme: ReactDOM.findDOMNode(this.refs.trayIconTheme).value
|
trayIconTheme: ReactDOM.findDOMNode(this.refs.trayIconTheme).value
|
||||||
});
|
});
|
||||||
|
setImmediate(this.saveConfig);
|
||||||
},
|
},
|
||||||
handleChangeAutoStart() {
|
handleChangeAutoStart() {
|
||||||
this.setState({
|
this.setState({
|
||||||
autostart: !this.refs.autostart.props.checked
|
autostart: !this.refs.autostart.props.checked
|
||||||
});
|
});
|
||||||
|
setImmediate(this.saveConfig);
|
||||||
},
|
},
|
||||||
handleChangeMinimizeToTray() {
|
handleChangeMinimizeToTray() {
|
||||||
const shouldMinimizeToTray = this.state.showTrayIcon && !this.refs.minimizeToTray.props.checked;
|
const shouldMinimizeToTray = this.state.showTrayIcon && !this.refs.minimizeToTray.props.checked;
|
||||||
@@ -134,16 +167,19 @@ const SettingsPage = React.createClass({
|
|||||||
this.setState({
|
this.setState({
|
||||||
minimizeToTray: shouldMinimizeToTray
|
minimizeToTray: shouldMinimizeToTray
|
||||||
});
|
});
|
||||||
|
setImmediate(this.saveConfig);
|
||||||
},
|
},
|
||||||
toggleShowTeamForm() {
|
toggleShowTeamForm() {
|
||||||
this.setState({
|
this.setState({
|
||||||
showAddTeamForm: !this.state.showAddTeamForm
|
showAddTeamForm: !this.state.showAddTeamForm
|
||||||
});
|
});
|
||||||
|
setImmediate(this.saveConfig);
|
||||||
},
|
},
|
||||||
setShowTeamFormVisibility(val) {
|
setShowTeamFormVisibility(val) {
|
||||||
this.setState({
|
this.setState({
|
||||||
showAddTeamForm: val
|
showAddTeamForm: val
|
||||||
});
|
});
|
||||||
|
setImmediate(this.saveConfig);
|
||||||
},
|
},
|
||||||
handleFlashWindow() {
|
handleFlashWindow() {
|
||||||
this.setState({
|
this.setState({
|
||||||
@@ -151,11 +187,13 @@ const SettingsPage = React.createClass({
|
|||||||
flashWindow: this.refs.flashWindow.props.checked ? 0 : 2
|
flashWindow: this.refs.flashWindow.props.checked ? 0 : 2
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
setImmediate(this.saveConfig);
|
||||||
},
|
},
|
||||||
handleShowUnreadBadge() {
|
handleShowUnreadBadge() {
|
||||||
this.setState({
|
this.setState({
|
||||||
showUnreadBadge: !this.refs.showUnreadBadge.props.checked
|
showUnreadBadge: !this.refs.showUnreadBadge.props.checked
|
||||||
});
|
});
|
||||||
|
setImmediate(this.saveConfig);
|
||||||
},
|
},
|
||||||
|
|
||||||
updateTeam(index, newData) {
|
updateTeam(index, newData) {
|
||||||
@@ -164,6 +202,7 @@ const SettingsPage = React.createClass({
|
|||||||
this.setState({
|
this.setState({
|
||||||
teams
|
teams
|
||||||
});
|
});
|
||||||
|
setImmediate(this.saveConfig);
|
||||||
},
|
},
|
||||||
|
|
||||||
addServer(team) {
|
addServer(team) {
|
||||||
@@ -172,6 +211,7 @@ const SettingsPage = React.createClass({
|
|||||||
this.setState({
|
this.setState({
|
||||||
teams
|
teams
|
||||||
});
|
});
|
||||||
|
setImmediate(this.saveConfig);
|
||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@@ -186,7 +226,7 @@ const SettingsPage = React.createClass({
|
|||||||
onTeamsChange={this.handleTeamsChange}
|
onTeamsChange={this.handleTeamsChange}
|
||||||
updateTeam={this.updateTeam}
|
updateTeam={this.updateTeam}
|
||||||
addServer={this.addServer}
|
addServer={this.addServer}
|
||||||
onTeamClick={this.backToIndexWithSave}
|
onTeamClick={backToIndex}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
@@ -388,7 +428,7 @@ const SettingsPage = React.createClass({
|
|||||||
</Navbar>
|
</Navbar>
|
||||||
<Grid
|
<Grid
|
||||||
className='settingsPage'
|
className='settingsPage'
|
||||||
style={{padding: '100px 15px'}}
|
style={{paddingTop: '100px'}}
|
||||||
>
|
>
|
||||||
<Row>
|
<Row>
|
||||||
<Col
|
<Col
|
||||||
@@ -415,26 +455,15 @@ const SettingsPage = React.createClass({
|
|||||||
<hr/>
|
<hr/>
|
||||||
{ optionsRow }
|
{ optionsRow }
|
||||||
</Grid>
|
</Grid>
|
||||||
<Navbar className='navbar-fixed-bottom'>
|
<div className='IndicatorContainer'>
|
||||||
<div
|
<ReactCSSTransitionGroup
|
||||||
className='text-right'
|
transitionName='AutoSaveIndicator'
|
||||||
style={settingsPage.footer}
|
transitionEnterTimeout={500}
|
||||||
|
transitionLeaveTimeout={1000}
|
||||||
>
|
>
|
||||||
<Button
|
{ this.state.savingState === 'done' ? null : <AutoSaveIndicator savingState={this.state.savingState}/> }
|
||||||
id='btnCancel'
|
</ReactCSSTransitionGroup>
|
||||||
className='btn-link'
|
</div>
|
||||||
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>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -3,6 +3,39 @@
|
|||||||
background: #eee;
|
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 {
|
.checkbox > label {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
@@ -24,6 +24,7 @@
|
|||||||
"react-addons-css-transition-group": "^15.4.1",
|
"react-addons-css-transition-group": "^15.4.1",
|
||||||
"react-bootstrap": "~0.30.7",
|
"react-bootstrap": "~0.30.7",
|
||||||
"react-dom": "^15.4.1",
|
"react-dom": "^15.4.1",
|
||||||
|
"underscore": "^1.8.3",
|
||||||
"yargs": "^3.32.0"
|
"yargs": "^3.32.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user