mirror of
https://github.com/balena-io/etcher.git
synced 2025-04-27 00:37:18 +00:00
Merge pull request #2368 from resin-io/refactor-settings
feat(gui): Persist local settings to config file
This commit is contained in:
commit
7c3f104d1b
@ -33,16 +33,16 @@ const EXIT_CODES = require('../../shared/exit-codes')
|
|||||||
const messages = require('../../shared/messages')
|
const messages = require('../../shared/messages')
|
||||||
const s3Packages = require('../../shared/s3-packages')
|
const s3Packages = require('../../shared/s3-packages')
|
||||||
const release = require('../../shared/release')
|
const release = require('../../shared/release')
|
||||||
const store = require('../../shared/store')
|
const store = require('./models/store')
|
||||||
const errors = require('../../shared/errors')
|
const errors = require('../../shared/errors')
|
||||||
const packageJSON = require('../../../package.json')
|
const packageJSON = require('../../../package.json')
|
||||||
const flashState = require('../../shared/models/flash-state')
|
const flashState = require('./models/flash-state')
|
||||||
const settings = require('./models/settings')
|
const settings = require('./models/settings')
|
||||||
const windowProgress = require('./os/window-progress')
|
const windowProgress = require('./os/window-progress')
|
||||||
const analytics = require('./modules/analytics')
|
const analytics = require('./modules/analytics')
|
||||||
const updateNotifier = require('./components/update-notifier')
|
const updateNotifier = require('./components/update-notifier')
|
||||||
const availableDrives = require('../../shared/models/available-drives')
|
const availableDrives = require('./models/available-drives')
|
||||||
const selectionState = require('../../shared/models/selection-state')
|
const selectionState = require('./models/selection-state')
|
||||||
const driveScanner = require('./modules/drive-scanner')
|
const driveScanner = require('./modules/drive-scanner')
|
||||||
const osDialog = require('./os/dialog')
|
const osDialog = require('./os/dialog')
|
||||||
const exceptionReporter = require('./modules/exception-reporter')
|
const exceptionReporter = require('./modules/exception-reporter')
|
||||||
@ -190,7 +190,7 @@ app.run(() => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
app.run(() => {
|
app.run(() => {
|
||||||
store.subscribe(() => {
|
store.observe(() => {
|
||||||
if (!flashState.isFlashing()) {
|
if (!flashState.isFlashing()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -21,8 +21,8 @@ const _ = require('lodash')
|
|||||||
const Bluebird = require('bluebird')
|
const Bluebird = require('bluebird')
|
||||||
const constraints = require('../../../../../shared/drive-constraints')
|
const constraints = require('../../../../../shared/drive-constraints')
|
||||||
const analytics = require('../../../modules/analytics')
|
const analytics = require('../../../modules/analytics')
|
||||||
const availableDrives = require('../../../../../shared/models/available-drives')
|
const availableDrives = require('../../../models/available-drives')
|
||||||
const selectionState = require('../../../../../shared/models/selection-state')
|
const selectionState = require('../../../models/selection-state')
|
||||||
const utils = require('../../../../../shared/utils')
|
const utils = require('../../../../../shared/utils')
|
||||||
|
|
||||||
module.exports = function (
|
module.exports = function (
|
||||||
|
@ -37,7 +37,7 @@ const Storage = require('../../../models/storage')
|
|||||||
const analytics = require('../../../modules/analytics')
|
const analytics = require('../../../modules/analytics')
|
||||||
const middleEllipsis = require('../../../utils/middle-ellipsis')
|
const middleEllipsis = require('../../../utils/middle-ellipsis')
|
||||||
const files = require('../../../../../shared/files')
|
const files = require('../../../../../shared/files')
|
||||||
const selectionState = require('../../../../../shared/models/selection-state')
|
const selectionState = require('../../../models/selection-state')
|
||||||
const imageStream = require('../../../../../sdk/image-stream')
|
const imageStream = require('../../../../../sdk/image-stream')
|
||||||
const errors = require('../../../../../shared/errors')
|
const errors = require('../../../../../shared/errors')
|
||||||
const messages = require('../../../../../shared/messages')
|
const messages = require('../../../../../shared/messages')
|
||||||
|
@ -16,8 +16,8 @@
|
|||||||
|
|
||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
const flashState = require('../../../../../shared/models/flash-state')
|
const flashState = require('../../../models/flash-state')
|
||||||
const selectionState = require('../../../../../shared/models/selection-state')
|
const selectionState = require('../../../models/selection-state')
|
||||||
const analytics = require('../../../modules/analytics')
|
const analytics = require('../../../modules/analytics')
|
||||||
|
|
||||||
module.exports = function (WarningModalService) {
|
module.exports = function (WarningModalService) {
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
const _ = require('lodash')
|
const _ = require('lodash')
|
||||||
const store = require('../store')
|
const store = require('./store')
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @summary Check if there are available drives
|
* @summary Check if there are available drives
|
@ -17,8 +17,8 @@
|
|||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
const _ = require('lodash')
|
const _ = require('lodash')
|
||||||
const store = require('../store')
|
const store = require('./store')
|
||||||
const units = require('../units')
|
const units = require('../../../shared/units')
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @summary Reset flash state
|
* @summary Reset flash state
|
@ -16,39 +16,49 @@
|
|||||||
|
|
||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
|
const electron = require('electron')
|
||||||
const Bluebird = require('bluebird')
|
const Bluebird = require('bluebird')
|
||||||
const _ = require('lodash')
|
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const os = require('os')
|
|
||||||
const Storage = require('./storage')
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @summary Local storage settings key
|
* @summary Number of spaces to indent JSON output with
|
||||||
|
* @type {Number}
|
||||||
|
* @constant
|
||||||
|
*/
|
||||||
|
const JSON_INDENT = 2
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @summary Userdata directory path
|
||||||
|
* @description
|
||||||
|
* Defaults to the following:
|
||||||
|
* - `%APPDATA%/etcher` on Windows
|
||||||
|
* - `$XDG_CONFIG_HOME/etcher` or `~/.config/etcher` on Linux
|
||||||
|
* - `~/Library/Application Support/etcher` on macOS
|
||||||
|
* See https://electronjs.org/docs/api/app#appgetpathname
|
||||||
* @constant
|
* @constant
|
||||||
* @type {String}
|
* @type {String}
|
||||||
*/
|
*/
|
||||||
const LOCAL_STORAGE_SETTINGS_KEY = 'etcher-settings'
|
const USER_DATA_DIR = electron.remote.app.getPath('userData')
|
||||||
const settingsStorage = new Storage(LOCAL_STORAGE_SETTINGS_KEY)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @summary Local settings filename
|
* @summary Configuration file path
|
||||||
* @constant
|
|
||||||
* @type {String}
|
* @type {String}
|
||||||
|
* @constant
|
||||||
*/
|
*/
|
||||||
const RCFILE = '.etcher.json'
|
const CONFIG_PATH = path.join(USER_DATA_DIR, 'config.json')
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @summary Read a local .etcherrc file
|
* @summary Read a local config.json file
|
||||||
* @function
|
* @function
|
||||||
* @public
|
* @private
|
||||||
*
|
*
|
||||||
* @param {String} filename - file path
|
* @param {String} filename - file path
|
||||||
* @fulfil {Object} - settings
|
* @fulfil {Object} - settings
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* readConfigFile('.etcherrc').then((settings) => {
|
* readConfigFile('config.json').then((settings) => {
|
||||||
* console.log(settings)
|
* console.log(settings)
|
||||||
* })
|
* })
|
||||||
*/
|
*/
|
||||||
@ -68,6 +78,35 @@ const readConfigFile = (filename) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @summary Write to the local configuration file
|
||||||
|
* @function
|
||||||
|
* @private
|
||||||
|
*
|
||||||
|
* @param {String} filename - file path
|
||||||
|
* @param {Object} data - data
|
||||||
|
* @fulfil {Object} data - data
|
||||||
|
* @returns {Promise}
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* writeConfigFile('config.json', { something: 'good' })
|
||||||
|
* .then(() => {
|
||||||
|
* console.log('data written')
|
||||||
|
* })
|
||||||
|
*/
|
||||||
|
const writeConfigFile = (filename, data) => {
|
||||||
|
return new Bluebird((resolve, reject) => {
|
||||||
|
const contents = JSON.stringify(data, null, JSON_INDENT)
|
||||||
|
fs.writeFile(filename, contents, (error) => {
|
||||||
|
if (error) {
|
||||||
|
reject(error)
|
||||||
|
} else {
|
||||||
|
resolve(data)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @summary Read all local settings
|
* @summary Read all local settings
|
||||||
* @function
|
* @function
|
||||||
@ -82,22 +121,7 @@ const readConfigFile = (filename) => {
|
|||||||
* });
|
* });
|
||||||
*/
|
*/
|
||||||
exports.readAll = () => {
|
exports.readAll = () => {
|
||||||
const homeConfigPath = process.platform === 'win32'
|
return readConfigFile(CONFIG_PATH)
|
||||||
? path.join(os.userInfo().homedir, RCFILE)
|
|
||||||
: path.join(os.userInfo().homedir, '.config', 'etcher', 'config.json')
|
|
||||||
const workdirConfigPath = path.join(process.cwd(), RCFILE)
|
|
||||||
const settings = {}
|
|
||||||
return Bluebird.try(() => {
|
|
||||||
_.merge(settings, settingsStorage.getAll())
|
|
||||||
}).return(readConfigFile(homeConfigPath))
|
|
||||||
.then((homeConfig) => {
|
|
||||||
_.merge(settings, homeConfig)
|
|
||||||
})
|
|
||||||
.return(readConfigFile(workdirConfigPath))
|
|
||||||
.then((workdirConfig) => {
|
|
||||||
_.merge(settings, workdirConfig)
|
|
||||||
})
|
|
||||||
.return(settings)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -106,6 +130,7 @@ exports.readAll = () => {
|
|||||||
* @public
|
* @public
|
||||||
*
|
*
|
||||||
* @param {Object} settings - settings
|
* @param {Object} settings - settings
|
||||||
|
* @fulfil {Object} settings - settings
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
@ -116,9 +141,7 @@ exports.readAll = () => {
|
|||||||
* });
|
* });
|
||||||
*/
|
*/
|
||||||
exports.writeAll = (settings) => {
|
exports.writeAll = (settings) => {
|
||||||
return Bluebird.try(() => {
|
return writeConfigFile(CONFIG_PATH, settings)
|
||||||
settingsStorage.setAll(settings)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -137,7 +160,13 @@ exports.writeAll = (settings) => {
|
|||||||
* });
|
* });
|
||||||
*/
|
*/
|
||||||
exports.clear = () => {
|
exports.clear = () => {
|
||||||
return Bluebird.try(() => {
|
return new Bluebird((resolve, reject) => {
|
||||||
settingsStorage.clearAll()
|
fs.unlink(CONFIG_PATH, (error) => {
|
||||||
|
if (error) {
|
||||||
|
reject(error)
|
||||||
|
} else {
|
||||||
|
resolve()
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
const _ = require('lodash')
|
const _ = require('lodash')
|
||||||
const store = require('../store')
|
const store = require('./store')
|
||||||
const availableDrives = require('./available-drives')
|
const availableDrives = require('./available-drives')
|
||||||
|
|
||||||
/**
|
/**
|
@ -23,58 +23,34 @@
|
|||||||
const _ = require('lodash')
|
const _ = require('lodash')
|
||||||
const Bluebird = require('bluebird')
|
const Bluebird = require('bluebird')
|
||||||
const localSettings = require('./local-settings')
|
const localSettings = require('./local-settings')
|
||||||
const store = require('../../../shared/store')
|
|
||||||
const errors = require('../../../shared/errors')
|
const errors = require('../../../shared/errors')
|
||||||
|
const release = require('../../../shared/release')
|
||||||
/**
|
const packageJSON = require('../../../../package.json')
|
||||||
* @summary Set a settings object
|
const debug = require('debug')('etcher:models:settings')
|
||||||
* @function
|
|
||||||
* @private
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Use this function with care, given that it will completely
|
|
||||||
* override any existing settings in both the redux store,
|
|
||||||
* and the local user configuration.
|
|
||||||
*
|
|
||||||
* This function is prepared to deal with any local configuration
|
|
||||||
* write issues by rolling back to the previous settings if so.
|
|
||||||
*
|
|
||||||
* @param {Object} settings - settings
|
|
||||||
* @returns {Promise}
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* setSettingsObject({ foo: 'bar' }).then(() => {
|
|
||||||
* console.log('Done!');
|
|
||||||
* });
|
|
||||||
*/
|
|
||||||
const setSettingsObject = (settings) => {
|
|
||||||
const currentSettings = exports.getAll()
|
|
||||||
|
|
||||||
return Bluebird.try(() => {
|
|
||||||
store.dispatch({
|
|
||||||
type: store.Actions.SET_SETTINGS,
|
|
||||||
data: settings
|
|
||||||
})
|
|
||||||
}).then(() => {
|
|
||||||
// Revert the application state if writing the data
|
|
||||||
// to the local machine was not successful
|
|
||||||
return localSettings.writeAll(settings).catch((error) => {
|
|
||||||
store.dispatch({
|
|
||||||
type: store.Actions.SET_SETTINGS,
|
|
||||||
data: currentSettings
|
|
||||||
})
|
|
||||||
|
|
||||||
throw error
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @summary Default settings
|
* @summary Default settings
|
||||||
* @constant
|
* @constant
|
||||||
* @type {Object}
|
* @type {Object}
|
||||||
*/
|
*/
|
||||||
const DEFAULT_SETTINGS = store.Defaults.get('settings').toJS()
|
const DEFAULT_SETTINGS = {
|
||||||
|
unsafeMode: false,
|
||||||
|
errorReporting: true,
|
||||||
|
unmountOnSuccess: true,
|
||||||
|
validateWriteOnSuccess: true,
|
||||||
|
updatesEnabled: packageJSON.updates.enabled && !_.includes([ 'rpm', 'deb' ], packageJSON.packageType),
|
||||||
|
includeUnstableUpdateChannel: !release.isStableRelease(packageJSON.version),
|
||||||
|
lastSleptUpdateNotifier: null,
|
||||||
|
lastSleptUpdateNotifierVersion: null,
|
||||||
|
desktopNotifications: true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @summary Settings state
|
||||||
|
* @type {Object}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
let settings = _.cloneDeep(DEFAULT_SETTINGS)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @summary Reset settings to their default values
|
* @summary Reset settings to their default values
|
||||||
@ -89,7 +65,11 @@ const DEFAULT_SETTINGS = store.Defaults.get('settings').toJS()
|
|||||||
* });
|
* });
|
||||||
*/
|
*/
|
||||||
exports.reset = () => {
|
exports.reset = () => {
|
||||||
return setSettingsObject(DEFAULT_SETTINGS)
|
debug('reset')
|
||||||
|
|
||||||
|
// TODO: Remove default settings from config file (?)
|
||||||
|
settings = _.cloneDeep(DEFAULT_SETTINGS)
|
||||||
|
return localSettings.writeAll(settings)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -97,7 +77,7 @@ exports.reset = () => {
|
|||||||
* @function
|
* @function
|
||||||
* @public
|
* @public
|
||||||
*
|
*
|
||||||
* @param {Object} settings - settings
|
* @param {Object} value - value
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
@ -107,14 +87,27 @@ exports.reset = () => {
|
|||||||
* console.log('Done!');
|
* console.log('Done!');
|
||||||
* });
|
* });
|
||||||
*/
|
*/
|
||||||
exports.assign = (settings) => {
|
exports.assign = (value) => {
|
||||||
if (_.isNil(settings)) {
|
debug('assign', value)
|
||||||
|
if (_.isNil(value)) {
|
||||||
return Bluebird.reject(errors.createError({
|
return Bluebird.reject(errors.createError({
|
||||||
title: 'Missing settings'
|
title: 'Missing settings'
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
return setSettingsObject(_.assign(exports.getAll(), settings))
|
if (!_.isPlainObject(value)) {
|
||||||
|
return Bluebird.reject(errors.createError({
|
||||||
|
title: 'Settings must be an object'
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
const newSettings = _.assign({}, settings, value)
|
||||||
|
|
||||||
|
return localSettings.writeAll(newSettings)
|
||||||
|
.then((updatedSettings) => {
|
||||||
|
// NOTE: Only update in memory settings when successfully written
|
||||||
|
settings = updatedSettings
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -130,7 +123,10 @@ exports.assign = (settings) => {
|
|||||||
* });
|
* });
|
||||||
*/
|
*/
|
||||||
exports.load = () => {
|
exports.load = () => {
|
||||||
return localSettings.readAll().then(exports.assign)
|
debug('load')
|
||||||
|
return localSettings.readAll().then((loadedSettings) => {
|
||||||
|
return _.assign(settings, loadedSettings)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -148,6 +144,7 @@ exports.load = () => {
|
|||||||
* });
|
* });
|
||||||
*/
|
*/
|
||||||
exports.set = (key, value) => {
|
exports.set = (key, value) => {
|
||||||
|
debug('set', key, value)
|
||||||
if (_.isNil(key)) {
|
if (_.isNil(key)) {
|
||||||
return Bluebird.reject(errors.createError({
|
return Bluebird.reject(errors.createError({
|
||||||
title: 'Missing setting key'
|
title: 'Missing setting key'
|
||||||
@ -160,9 +157,16 @@ exports.set = (key, value) => {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
return exports.assign({
|
const previousValue = settings[key]
|
||||||
[key]: value
|
|
||||||
})
|
settings[key] = value
|
||||||
|
|
||||||
|
return localSettings.writeAll(settings)
|
||||||
|
.catch((error) => {
|
||||||
|
// Revert to previous value if persisting settings failed
|
||||||
|
settings[key] = previousValue
|
||||||
|
throw error
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -177,7 +181,7 @@ exports.set = (key, value) => {
|
|||||||
* const value = settings.get('unmountOnSuccess');
|
* const value = settings.get('unmountOnSuccess');
|
||||||
*/
|
*/
|
||||||
exports.get = (key) => {
|
exports.get = (key) => {
|
||||||
return _.get(exports.getAll(), [ key ])
|
return _.cloneDeep(_.get(settings, [ key ]))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -192,5 +196,22 @@ exports.get = (key) => {
|
|||||||
* console.log(allSettings.unmountOnSuccess);
|
* console.log(allSettings.unmountOnSuccess);
|
||||||
*/
|
*/
|
||||||
exports.getAll = () => {
|
exports.getAll = () => {
|
||||||
return store.getState().get('settings').toJS()
|
debug('getAll')
|
||||||
|
return _.cloneDeep(settings)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @summary Get the default setting values
|
||||||
|
* @function
|
||||||
|
* @public
|
||||||
|
*
|
||||||
|
* @returns {Object} all setting values
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const defaults = settings.getDefaults();
|
||||||
|
* console.log(defaults.unmountOnSuccess);
|
||||||
|
*/
|
||||||
|
exports.getDefaults = () => {
|
||||||
|
debug('getDefaults')
|
||||||
|
return _.cloneDeep(DEFAULT_SETTINGS)
|
||||||
}
|
}
|
||||||
|
@ -20,13 +20,11 @@ const Immutable = require('immutable')
|
|||||||
const _ = require('lodash')
|
const _ = require('lodash')
|
||||||
const redux = require('redux')
|
const redux = require('redux')
|
||||||
const uuidV4 = require('uuid/v4')
|
const uuidV4 = require('uuid/v4')
|
||||||
const constraints = require('./drive-constraints')
|
const constraints = require('../../../shared/drive-constraints')
|
||||||
const supportedFormats = require('./supported-formats')
|
const supportedFormats = require('../../../shared/supported-formats')
|
||||||
const errors = require('./errors')
|
const errors = require('../../../shared/errors')
|
||||||
const release = require('./release')
|
const fileExtensions = require('../../../shared/file-extensions')
|
||||||
const fileExtensions = require('./file-extensions')
|
const utils = require('../../../shared/utils')
|
||||||
const utils = require('./utils')
|
|
||||||
const packageJSON = require('../../package.json')
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @summary Verify and throw if any state fields are nil
|
* @summary Verify and throw if any state fields are nil
|
||||||
@ -95,17 +93,6 @@ const DEFAULT_STATE = Immutable.fromJS({
|
|||||||
percentage: 0,
|
percentage: 0,
|
||||||
speed: 0,
|
speed: 0,
|
||||||
totalSpeed: 0
|
totalSpeed: 0
|
||||||
},
|
|
||||||
settings: {
|
|
||||||
unsafeMode: false,
|
|
||||||
errorReporting: true,
|
|
||||||
unmountOnSuccess: true,
|
|
||||||
validateWriteOnSuccess: true,
|
|
||||||
updatesEnabled: packageJSON.updates.enabled && !_.includes([ 'rpm', 'deb' ], packageJSON.packageType),
|
|
||||||
includeUnstableUpdateChannel: !release.isStableRelease(packageJSON.version),
|
|
||||||
lastSleptUpdateNotifier: null,
|
|
||||||
lastSleptUpdateNotifierVersion: null,
|
|
||||||
desktopNotifications: true
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -123,8 +110,7 @@ const ACTIONS = _.fromPairs(_.map([
|
|||||||
'SELECT_DRIVE',
|
'SELECT_DRIVE',
|
||||||
'SELECT_IMAGE',
|
'SELECT_IMAGE',
|
||||||
'DESELECT_DRIVE',
|
'DESELECT_DRIVE',
|
||||||
'DESELECT_IMAGE',
|
'DESELECT_IMAGE'
|
||||||
'SET_SETTINGS'
|
|
||||||
], (message) => {
|
], (message) => {
|
||||||
return [ message, message ]
|
return [ message, message ]
|
||||||
}))
|
}))
|
||||||
@ -512,34 +498,6 @@ const storeReducer = (state = DEFAULT_STATE, action) => {
|
|||||||
return state.deleteIn([ 'selection', 'image' ])
|
return state.deleteIn([ 'selection', 'image' ])
|
||||||
}
|
}
|
||||||
|
|
||||||
case ACTIONS.SET_SETTINGS: {
|
|
||||||
// Type: action.data : SettingsObject
|
|
||||||
|
|
||||||
if (!action.data) {
|
|
||||||
throw errors.createError({
|
|
||||||
title: 'Missing settings'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_.isPlainObject(action.data)) {
|
|
||||||
throw errors.createError({
|
|
||||||
title: `Invalid settings: ${action.data}`
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const invalidPair = _.find(_.toPairs(action.data), (pair) => {
|
|
||||||
return _.isObject(_.last(pair))
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!_.isNil(invalidPair)) {
|
|
||||||
throw errors.createError({
|
|
||||||
title: `Invalid setting value: ${_.last(invalidPair)} for ${_.first(invalidPair)}`
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return state.setIn([ 'settings' ], Immutable.fromJS(action.data))
|
|
||||||
}
|
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
@ -550,3 +508,34 @@ module.exports = _.merge(redux.createStore(storeReducer, DEFAULT_STATE), {
|
|||||||
Actions: ACTIONS,
|
Actions: ACTIONS,
|
||||||
Defaults: DEFAULT_STATE
|
Defaults: DEFAULT_STATE
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @summary Observe the store for changes
|
||||||
|
* @param {Function} onChange - change handler
|
||||||
|
* @returns {Function} unsubscribe
|
||||||
|
* @example
|
||||||
|
* store.observe((newState) => {
|
||||||
|
* // ...
|
||||||
|
* })
|
||||||
|
*/
|
||||||
|
module.exports.observe = (onChange) => {
|
||||||
|
let currentState = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @summary Internal change detection handler
|
||||||
|
* @private
|
||||||
|
* @example
|
||||||
|
* store.subscribe(changeHandler)
|
||||||
|
*/
|
||||||
|
const changeHandler = () => {
|
||||||
|
const nextState = module.exports.getState()
|
||||||
|
if (!_.isEqual(nextState, currentState)) {
|
||||||
|
currentState = nextState
|
||||||
|
onChange(currentState)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
changeHandler()
|
||||||
|
|
||||||
|
return module.exports.subscribe(changeHandler)
|
||||||
|
}
|
@ -24,14 +24,14 @@ const ipc = require('node-ipc')
|
|||||||
const isRunningInAsar = require('electron-is-running-in-asar')
|
const isRunningInAsar = require('electron-is-running-in-asar')
|
||||||
const electron = require('electron')
|
const electron = require('electron')
|
||||||
const settings = require('../models/settings')
|
const settings = require('../models/settings')
|
||||||
const flashState = require('../../../shared/models/flash-state')
|
const flashState = require('../models/flash-state')
|
||||||
const errors = require('../../../shared/errors')
|
const errors = require('../../../shared/errors')
|
||||||
const permissions = require('../../../shared/permissions')
|
const permissions = require('../../../shared/permissions')
|
||||||
const windowProgress = require('../os/window-progress')
|
const windowProgress = require('../os/window-progress')
|
||||||
const analytics = require('../modules/analytics')
|
const analytics = require('../modules/analytics')
|
||||||
const updateLock = require('./update-lock')
|
const updateLock = require('./update-lock')
|
||||||
const packageJSON = require('../../../../package.json')
|
const packageJSON = require('../../../../package.json')
|
||||||
const selectionState = require('../../../shared/models/selection-state')
|
const selectionState = require('../models/selection-state')
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @summary Number of threads per CPU to allocate to the UV_THREADPOOL
|
* @summary Number of threads per CPU to allocate to the UV_THREADPOOL
|
||||||
|
@ -18,8 +18,8 @@
|
|||||||
|
|
||||||
const _ = require('lodash')
|
const _ = require('lodash')
|
||||||
const settings = require('../../../models/settings')
|
const settings = require('../../../models/settings')
|
||||||
const flashState = require('../../../../../shared/models/flash-state')
|
const flashState = require('../../../models/flash-state')
|
||||||
const selectionState = require('../../../../../shared/models/selection-state')
|
const selectionState = require('../../../models/selection-state')
|
||||||
const analytics = require('../../../modules/analytics')
|
const analytics = require('../../../modules/analytics')
|
||||||
const updateLock = require('../../../modules/update-lock')
|
const updateLock = require('../../../modules/update-lock')
|
||||||
const messages = require('../../../../../shared/messages')
|
const messages = require('../../../../../shared/messages')
|
||||||
|
@ -20,7 +20,7 @@ const _ = require('lodash')
|
|||||||
const angular = require('angular')
|
const angular = require('angular')
|
||||||
const prettyBytes = require('pretty-bytes')
|
const prettyBytes = require('pretty-bytes')
|
||||||
const settings = require('../../../models/settings')
|
const settings = require('../../../models/settings')
|
||||||
const selectionState = require('../../../../../shared/models/selection-state')
|
const selectionState = require('../../../models/selection-state')
|
||||||
const analytics = require('../../../modules/analytics')
|
const analytics = require('../../../modules/analytics')
|
||||||
const exceptionReporter = require('../../../modules/exception-reporter')
|
const exceptionReporter = require('../../../modules/exception-reporter')
|
||||||
const utils = require('../../../../../shared/utils')
|
const utils = require('../../../../../shared/utils')
|
||||||
|
@ -18,16 +18,16 @@
|
|||||||
|
|
||||||
const _ = require('lodash')
|
const _ = require('lodash')
|
||||||
const messages = require('../../../../../shared/messages')
|
const messages = require('../../../../../shared/messages')
|
||||||
const flashState = require('../../../../../shared/models/flash-state')
|
const flashState = require('../../../models/flash-state')
|
||||||
const driveScanner = require('../../../modules/drive-scanner')
|
const driveScanner = require('../../../modules/drive-scanner')
|
||||||
const progressStatus = require('../../../modules/progress-status')
|
const progressStatus = require('../../../modules/progress-status')
|
||||||
const notification = require('../../../os/notification')
|
const notification = require('../../../os/notification')
|
||||||
const exceptionReporter = require('../../../modules/exception-reporter')
|
const exceptionReporter = require('../../../modules/exception-reporter')
|
||||||
const imageWriter = require('../../../modules/image-writer')
|
const imageWriter = require('../../../modules/image-writer')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const store = require('../../../../../shared/store')
|
const store = require('../../../models/store')
|
||||||
const constraints = require('../../../../../shared/drive-constraints')
|
const constraints = require('../../../../../shared/drive-constraints')
|
||||||
const availableDrives = require('../../../../../shared/models/available-drives')
|
const availableDrives = require('../../../models/available-drives')
|
||||||
|
|
||||||
module.exports = function (
|
module.exports = function (
|
||||||
$q,
|
$q,
|
||||||
@ -139,7 +139,7 @@ module.exports = function (
|
|||||||
|
|
||||||
// Trigger Angular digests along with store updates, as the flash state
|
// Trigger Angular digests along with store updates, as the flash state
|
||||||
// updates. Without this there is essentially no progress to watch.
|
// updates. Without this there is essentially no progress to watch.
|
||||||
const unsubscribe = store.subscribe($timeout)
|
const unsubscribe = store.observe($timeout)
|
||||||
|
|
||||||
const iconPath = '../../../assets/icon.png'
|
const iconPath = '../../../assets/icon.png'
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ const errors = require('../../../../../shared/errors')
|
|||||||
const imageStream = require('../../../../../sdk/image-stream')
|
const imageStream = require('../../../../../sdk/image-stream')
|
||||||
const supportedFormats = require('../../../../../shared/supported-formats')
|
const supportedFormats = require('../../../../../shared/supported-formats')
|
||||||
const analytics = require('../../../modules/analytics')
|
const analytics = require('../../../modules/analytics')
|
||||||
const selectionState = require('../../../../../shared/models/selection-state')
|
const selectionState = require('../../../models/selection-state')
|
||||||
const osDialog = require('../../../os/dialog')
|
const osDialog = require('../../../os/dialog')
|
||||||
const exceptionReporter = require('../../../modules/exception-reporter')
|
const exceptionReporter = require('../../../modules/exception-reporter')
|
||||||
|
|
||||||
|
@ -17,11 +17,11 @@
|
|||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
const settings = require('../../../models/settings')
|
const settings = require('../../../models/settings')
|
||||||
const flashState = require('../../../../../shared/models/flash-state')
|
const flashState = require('../../../models/flash-state')
|
||||||
const analytics = require('../../../modules/analytics')
|
const analytics = require('../../../modules/analytics')
|
||||||
const exceptionReporter = require('../../../modules/exception-reporter')
|
const exceptionReporter = require('../../../modules/exception-reporter')
|
||||||
const availableDrives = require('../../../../../shared/models/available-drives')
|
const availableDrives = require('../../../models/available-drives')
|
||||||
const selectionState = require('../../../../../shared/models/selection-state')
|
const selectionState = require('../../../models/selection-state')
|
||||||
const driveConstraints = require('../../../../../shared/drive-constraints')
|
const driveConstraints = require('../../../../../shared/drive-constraints')
|
||||||
const messages = require('../../../../../shared/messages')
|
const messages = require('../../../../../shared/messages')
|
||||||
|
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
const m = require('mochainon')
|
const m = require('mochainon')
|
||||||
const _ = require('lodash')
|
const _ = require('lodash')
|
||||||
const Bluebird = require('bluebird')
|
const Bluebird = require('bluebird')
|
||||||
const store = require('../../../lib/shared/store')
|
|
||||||
const settings = require('../../../lib/gui/app/models/settings')
|
const settings = require('../../../lib/gui/app/models/settings')
|
||||||
const localSettings = require('../../../lib/gui/app/models/local-settings')
|
const localSettings = require('../../../lib/gui/app/models/local-settings')
|
||||||
|
|
||||||
@ -28,7 +27,7 @@ describe('Browser: settings', function () {
|
|||||||
return settings.reset()
|
return settings.reset()
|
||||||
})
|
})
|
||||||
|
|
||||||
const DEFAULT_SETTINGS = store.Defaults.get('settings').toJS()
|
const DEFAULT_SETTINGS = settings.getDefaults()
|
||||||
|
|
||||||
it('should be able to set and read values', function () {
|
it('should be able to set and read values', function () {
|
||||||
m.chai.expect(settings.get('foo')).to.be.undefined
|
m.chai.expect(settings.get('foo')).to.be.undefined
|
||||||
@ -82,17 +81,6 @@ describe('Browser: settings', function () {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should throw if setting an array', function (done) {
|
|
||||||
settings.assign({
|
|
||||||
foo: 'bar',
|
|
||||||
bar: [ 1, 2, 3 ]
|
|
||||||
}).asCallback((error) => {
|
|
||||||
m.chai.expect(error).to.be.an.instanceof(Error)
|
|
||||||
m.chai.expect(error.message).to.equal('Invalid setting value: 1,2,3 for bar')
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should not override all settings', function () {
|
it('should not override all settings', function () {
|
||||||
return settings.assign({
|
return settings.assign({
|
||||||
foo: 'bar',
|
foo: 'bar',
|
||||||
@ -105,24 +93,6 @@ describe('Browser: settings', function () {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should not store invalid settings to the local machine', function () {
|
|
||||||
return localSettings.readAll().then((data) => {
|
|
||||||
m.chai.expect(data.foo).to.be.undefined
|
|
||||||
|
|
||||||
return new Bluebird((resolve) => {
|
|
||||||
settings.assign({
|
|
||||||
foo: [ 1, 2, 3 ]
|
|
||||||
}).asCallback((error) => {
|
|
||||||
m.chai.expect(error).to.be.an.instanceof(Error)
|
|
||||||
m.chai.expect(error.message).to.equal('Invalid setting value: 1,2,3 for foo')
|
|
||||||
return resolve()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}).then(localSettings.readAll).then((data) => {
|
|
||||||
m.chai.expect(data.foo).to.be.undefined
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should store the settings to the local machine', function () {
|
it('should store the settings to the local machine', function () {
|
||||||
return localSettings.readAll().then((data) => {
|
return localSettings.readAll().then((data) => {
|
||||||
m.chai.expect(data.foo).to.be.undefined
|
m.chai.expect(data.foo).to.be.undefined
|
||||||
@ -206,20 +176,10 @@ describe('Browser: settings', function () {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should throw if setting an object', function (done) {
|
|
||||||
settings.set('foo', {
|
|
||||||
setting: 1
|
|
||||||
}).asCallback((error) => {
|
|
||||||
m.chai.expect(error).to.be.an.instanceof(Error)
|
|
||||||
m.chai.expect(error.message).to.equal('Invalid setting value: [object Object] for foo')
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should throw if setting an array', function (done) {
|
it('should throw if setting an array', function (done) {
|
||||||
settings.set('foo', [ 1, 2, 3 ]).asCallback((error) => {
|
settings.assign([ 1, 2, 3 ]).asCallback((error) => {
|
||||||
m.chai.expect(error).to.be.an.instanceof(Error)
|
m.chai.expect(error).to.be.an.instanceof(Error)
|
||||||
m.chai.expect(error.message).to.equal('Invalid setting value: 1,2,3 for foo')
|
m.chai.expect(error.message).to.equal('Settings must be an object')
|
||||||
done()
|
done()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -242,22 +202,6 @@ describe('Browser: settings', function () {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should not store invalid settings to the local machine', function () {
|
|
||||||
return localSettings.readAll().then((data) => {
|
|
||||||
m.chai.expect(data.foo).to.be.undefined
|
|
||||||
|
|
||||||
return new Bluebird((resolve) => {
|
|
||||||
settings.set('foo', [ 1, 2, 3 ]).asCallback((error) => {
|
|
||||||
m.chai.expect(error).to.be.an.instanceof(Error)
|
|
||||||
m.chai.expect(error.message).to.equal('Invalid setting value: 1,2,3 for foo')
|
|
||||||
return resolve()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}).then(localSettings.readAll).then((data) => {
|
|
||||||
m.chai.expect(data.foo).to.be.undefined
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should not change the application state if storing to the local machine results in an error', function (done) {
|
it('should not change the application state if storing to the local machine results in an error', function (done) {
|
||||||
settings.set('foo', 'bar').then(() => {
|
settings.set('foo', 'bar').then(() => {
|
||||||
m.chai.expect(settings.get('foo')).to.equal('bar')
|
m.chai.expect(settings.get('foo')).to.equal('bar')
|
||||||
|
@ -4,7 +4,7 @@ const m = require('mochainon')
|
|||||||
const ipc = require('node-ipc')
|
const ipc = require('node-ipc')
|
||||||
const angular = require('angular')
|
const angular = require('angular')
|
||||||
const Bluebird = require('bluebird')
|
const Bluebird = require('bluebird')
|
||||||
const flashState = require('../../../lib/shared/models/flash-state')
|
const flashState = require('../../../lib/gui/app/models/flash-state')
|
||||||
const imageWriter = require('../../../lib/gui/app/modules/image-writer')
|
const imageWriter = require('../../../lib/gui/app/modules/image-writer')
|
||||||
require('angular-mocks')
|
require('angular-mocks')
|
||||||
|
|
||||||
|
@ -22,9 +22,9 @@ const fs = require('fs')
|
|||||||
const path = require('path')
|
const path = require('path')
|
||||||
const supportedFormats = require('../../../lib/shared/supported-formats')
|
const supportedFormats = require('../../../lib/shared/supported-formats')
|
||||||
const angular = require('angular')
|
const angular = require('angular')
|
||||||
const flashState = require('../../../lib/shared/models/flash-state')
|
const flashState = require('../../../lib/gui/app/models/flash-state')
|
||||||
const availableDrives = require('../../../lib/shared/models/available-drives')
|
const availableDrives = require('../../../lib/gui/app/models/available-drives')
|
||||||
const selectionState = require('../../../lib/shared/models/selection-state')
|
const selectionState = require('../../../lib/gui/app/models/selection-state')
|
||||||
require('angular-mocks')
|
require('angular-mocks')
|
||||||
|
|
||||||
// Mock HTML requires by reading from the file-system
|
// Mock HTML requires by reading from the file-system
|
||||||
|
@ -18,8 +18,8 @@
|
|||||||
|
|
||||||
const m = require('mochainon')
|
const m = require('mochainon')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const availableDrives = require('../../../lib/shared/models/available-drives')
|
const availableDrives = require('../../../lib/gui/app/models/available-drives')
|
||||||
const selectionState = require('../../../lib/shared/models/selection-state')
|
const selectionState = require('../../../lib/gui/app/models/selection-state')
|
||||||
const constraints = require('../../../lib/shared/drive-constraints')
|
const constraints = require('../../../lib/shared/drive-constraints')
|
||||||
|
|
||||||
describe('Model: availableDrives', function () {
|
describe('Model: availableDrives', function () {
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
const m = require('mochainon')
|
const m = require('mochainon')
|
||||||
const flashState = require('../../../lib/shared/models/flash-state')
|
const flashState = require('../../../lib/gui/app/models/flash-state')
|
||||||
|
|
||||||
describe('Model: flashState', function () {
|
describe('Model: flashState', function () {
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
|
@ -19,8 +19,8 @@
|
|||||||
const m = require('mochainon')
|
const m = require('mochainon')
|
||||||
const _ = require('lodash')
|
const _ = require('lodash')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const availableDrives = require('../../../lib/shared/models/available-drives')
|
const availableDrives = require('../../../lib/gui/app/models/available-drives')
|
||||||
const selectionState = require('../../../lib/shared/models/selection-state')
|
const selectionState = require('../../../lib/gui/app/models/selection-state')
|
||||||
|
|
||||||
describe('Model: selectionState', function () {
|
describe('Model: selectionState', function () {
|
||||||
describe('given a clean state', function () {
|
describe('given a clean state', function () {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user