refactor: store settings in redux store

The state data structure now contains a property called `settings`,
which is a map containing all setting values.

The list of supported settings can be calculated by retrieving the keys
from the `settings` object, which means that if we support a setting, we
must include a default.

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
This commit is contained in:
Juan Cruz Viotti
2016-06-24 15:02:03 -04:00
parent 5c8a80e6d5
commit acb0de2ba8
4 changed files with 54 additions and 85 deletions

View File

@@ -21,41 +21,11 @@
*/
const angular = require('angular');
const _ = require('lodash');
require('ngstorage');
const Store = require('./store');
const MODULE_NAME = 'Etcher.Models.Settings';
const SettingsModel = angular.module(MODULE_NAME, [
'ngStorage'
]);
const SettingsModel = angular.module(MODULE_NAME, []);
SettingsModel.service('SettingsModel', function($localStorage) {
/**
* @summary Default settings
* @type {Object}
* @private
*/
const DEFAULT_SETTINGS = {
errorReporting: true,
unmountOnSuccess: true,
validateWriteOnSuccess: true,
sleepUpdateCheck: false,
lastUpdateNotify: null
};
/**
* @summary Settings data
* @type {Object}
* @private
*/
const data = $localStorage.$default(DEFAULT_SETTINGS);
/**
* @summary Supported settings keys
* @type {String[]}
* @private
*/
this.SUPPORTED_KEYS = _.keys(DEFAULT_SETTINGS);
SettingsModel.service('SettingsModel', function() {
/**
* @summary Set a setting value
@@ -69,23 +39,13 @@ SettingsModel.service('SettingsModel', function($localStorage) {
* SettingsModel.set('unmountOnSuccess', true);
*/
this.set = (key, value) => {
if (!key) {
throw new Error('Missing setting key');
}
if (!_.isString(key)) {
throw new Error(`Invalid setting key: ${key}`);
}
if (!_.includes(this.SUPPORTED_KEYS, key)) {
throw new Error(`Unsupported setting: ${key}`);
}
if (_.isObject(value)) {
throw new Error(`Invalid setting value: ${value}`);
}
data[key] = value;
Store.dispatch({
type: Store.Actions.SET_SETTING,
data: {
key,
value
}
});
};
/**
@@ -100,15 +60,7 @@ SettingsModel.service('SettingsModel', function($localStorage) {
* const value = SettingsModel.get('unmountOnSuccess');
*/
this.get = (key) => {
if (!key) {
throw new Error('Missing setting key');
}
if (!_.isString(key)) {
throw new Error(`Invalid setting key: ${key}`);
}
return data[key];
return this.getAll()[key];
};
/**
@@ -123,7 +75,7 @@ SettingsModel.service('SettingsModel', function($localStorage) {
* console.log(allSettings.unmountOnSuccess);
*/
this.getAll = () => {
return data;
return Store.getState().get('settings').toJS();
};
});

View File

@@ -34,6 +34,13 @@ const DEFAULT_STATE = Immutable.fromJS({
flashState: {
percentage: 0,
speed: 0
},
settings: {
errorReporting: true,
unmountOnSuccess: true,
validateWriteOnSuccess: true,
sleepUpdateCheck: false,
lastUpdateNotify: null
}
});
@@ -51,7 +58,8 @@ const ACTIONS = _.fromPairs(_.map([
'SELECT_DRIVE',
'SELECT_IMAGE',
'REMOVE_DRIVE',
'REMOVE_IMAGE'
'REMOVE_IMAGE',
'SET_SETTING'
], (message) => {
return [ message, message ];
}));
@@ -263,6 +271,29 @@ const storeReducer = (state, action) => {
return state.deleteIn([ 'selection', 'image' ]);
}
case ACTIONS.SET_SETTING: {
const key = action.data.key;
const value = action.data.value;
if (!key) {
throw new Error('Missing setting key');
}
if (!_.isString(key)) {
throw new Error(`Invalid setting key: ${key}`);
}
if (!DEFAULT_STATE.get('settings').has(key)) {
throw new Error(`Unsupported setting: ${key}`);
}
if (_.isObject(value)) {
throw new Error(`Invalid setting value: ${value}`);
}
return state.setIn([ 'settings', key ], value);
}
default: {
return state;
}
@@ -271,5 +302,6 @@ const storeReducer = (state, action) => {
};
module.exports = _.merge(redux.createStore(storeReducer), {
Actions: ACTIONS
Actions: ACTIONS,
Defaults: DEFAULT_STATE
});

View File

@@ -72,7 +72,6 @@
"immutable": "^3.8.1",
"is-elevated": "^1.0.0",
"lodash": "^4.5.1",
"ngstorage": "^0.3.10",
"redux": "^3.5.2",
"resin-cli-errors": "^1.2.0",
"resin-cli-form": "^1.4.1",

View File

@@ -4,6 +4,7 @@ const m = require('mochainon');
const _ = require('lodash');
const angular = require('angular');
require('angular-mocks');
const Store = require('../../../lib/gui/models/store');
describe('Browser: SettingsModel', function() {
@@ -13,6 +14,7 @@ describe('Browser: SettingsModel', function() {
describe('SettingsModel', function() {
const SUPPORTED_KEYS = _.keys(Store.Defaults.get('settings').toJS());
let SettingsModel;
beforeEach(angular.mock.inject(function(_SettingsModel_) {
@@ -24,13 +26,13 @@ describe('Browser: SettingsModel', function() {
});
afterEach(function() {
_.each(SettingsModel.SUPPORTED_KEYS, (supportedKey) => {
_.each(SUPPORTED_KEYS, (supportedKey) => {
SettingsModel.set(supportedKey, this.settings[supportedKey]);
});
});
it('should be able to set and read values', function() {
const keyUnderTest = _.first(SettingsModel.SUPPORTED_KEYS);
const keyUnderTest = _.first(SUPPORTED_KEYS);
const originalValue = SettingsModel.get(keyUnderTest);
SettingsModel.set(keyUnderTest, !originalValue);
@@ -39,22 +41,6 @@ describe('Browser: SettingsModel', function() {
m.chai.expect(SettingsModel.get(keyUnderTest)).to.equal(originalValue);
});
describe('.get()', function() {
it('should throw if no key', function() {
m.chai.expect(function() {
SettingsModel.get(null);
}).to.throw('Missing setting key');
});
it('should throw if key is not a string', function() {
m.chai.expect(function() {
SettingsModel.get(1234);
}).to.throw('Invalid setting key: 1234');
});
});
describe('.set()', function() {
it('should throw if the key is not supported', function() {
@@ -76,7 +62,7 @@ describe('Browser: SettingsModel', function() {
});
it('should throw if setting an object', function() {
const keyUnderTest = _.first(SettingsModel.SUPPORTED_KEYS);
const keyUnderTest = _.first(SUPPORTED_KEYS);
m.chai.expect(function() {
SettingsModel.set(keyUnderTest, {
x: 1
@@ -85,14 +71,14 @@ describe('Browser: SettingsModel', function() {
});
it('should throw if setting an array', function() {
const keyUnderTest = _.first(SettingsModel.SUPPORTED_KEYS);
const keyUnderTest = _.first(SUPPORTED_KEYS);
m.chai.expect(function() {
SettingsModel.set(keyUnderTest, [ 1, 2, 3 ]);
}).to.throw('Invalid setting value: 1,2,3');
});
it('should set the key to undefined if no value', function() {
const keyUnderTest = _.first(SettingsModel.SUPPORTED_KEYS);
const keyUnderTest = _.first(SUPPORTED_KEYS);
SettingsModel.set(keyUnderTest);
m.chai.expect(SettingsModel.get(keyUnderTest)).to.be.undefined;
});
@@ -104,7 +90,7 @@ describe('Browser: SettingsModel', function() {
it('should be able to read all values', function() {
const allValues = SettingsModel.getAll();
_.each(SettingsModel.SUPPORTED_KEYS, function(supportedKey) {
_.each(SUPPORTED_KEYS, function(supportedKey) {
m.chai.expect(allValues[supportedKey]).to.equal(SettingsModel.get(supportedKey));
});
});