diff --git a/lib/gui/app/components/file-selector/controllers/file-selector.js b/lib/gui/app/components/file-selector/controllers/file-selector.js index 342448d8..ca703296 100644 --- a/lib/gui/app/components/file-selector/controllers/file-selector.js +++ b/lib/gui/app/components/file-selector/controllers/file-selector.js @@ -48,11 +48,10 @@ module.exports = function ( * @example * FileSelectorController.getFolderConstraint() */ - this.getFolderConstraints = utils.memoize(() => { - // TODO(Shou): get this dynamically from the mountpoint of a specific port in Etcher Pro + this.getFolderConstraint = utils.memoize(() => { return settings.has('fileBrowserConstraintPath') - ? settings.get('fileBrowserConstraintPath').split(',') - : [] + ? settings.get('fileBrowserConstraintPath') + : '' }, angular.equals) /** @@ -66,7 +65,6 @@ module.exports = function ( * */ this.getPath = () => { - const [ constraint ] = this.getFolderConstraints() - return constraint || os.homedir() + return this.getFolderConstraint() ? '/' : os.homedir() } } diff --git a/lib/gui/app/components/file-selector/file-selector/file-list.jsx b/lib/gui/app/components/file-selector/file-selector/file-list.jsx index 58433c43..fca8d7f0 100644 --- a/lib/gui/app/components/file-selector/file-selector/file-list.jsx +++ b/lib/gui/app/components/file-selector/file-selector/file-list.jsx @@ -228,15 +228,38 @@ const File = styled(UnstyledFile)` class FileList extends React.Component { constructor (props) { super(props) + this.state = { path: props.path, highlighted: null, files: [], } + + debug('FileList', props) } readdir (dirname) { debug('FileList:readdir', dirname) + + if (this.props.constraintPath && dirname === '/') { + if (this.props.constraint) { + const mountpoints = this.props.constraint.mountpoints.map(( mount ) => { + const entry = new files.FileEntry(mount.path, { + size: 0, + isFile: () => false, + isDirectory: () => true + }) + entry.name = mount.label + return entry + }) + debug('FileList:readdir', mountpoints) + window.requestAnimationFrame(() => { + this.setState({ files: mountpoints }) + }) + } + return + } + files.readdirAsync(dirname).then((files) => { window.requestAnimationFrame(() => { this.setState({ files: files }) @@ -263,8 +286,10 @@ class FileList extends React.Component { shouldComponentUpdate (nextProps, nextState) { const shouldUpdate = (this.state.files !== nextState.files) debug('FileList:shouldComponentUpdate', shouldUpdate) - if (this.props.path !== nextProps.path) { - this.readdir(nextProps.path) + if (this.props.path !== nextProps.path || this.props.constraint !== nextProps.constraint) { + process.nextTick(() => { + this.readdir(nextProps.path) + }) } return shouldUpdate } @@ -293,11 +318,4 @@ class FileList extends React.Component { } } -FileList.propTypes = { - path: propTypes.string, - onNavigate: propTypes.func, - onSelect: propTypes.func, - constraints: propTypes.arrayOf(propTypes.string) -} - module.exports = FileList diff --git a/lib/gui/app/components/file-selector/file-selector/file-selector.jsx b/lib/gui/app/components/file-selector/file-selector/file-selector.jsx index f52a672e..59fd3386 100644 --- a/lib/gui/app/components/file-selector/file-selector/file-selector.jsx +++ b/lib/gui/app/components/file-selector/file-selector/file-selector.jsx @@ -28,6 +28,7 @@ const colors = require('./colors') const Breadcrumbs = require('./path-breadcrumbs') const FileList = require('./file-list') const RecentFiles = require('./recent-files') +const files = require('../../../models/files') const selectionState = require('../../../models/selection-state') const osDialog = require('../../../os/dialog') @@ -113,11 +114,20 @@ const FilePath = styled(UnstyledFilePath)` class FileSelector extends React.PureComponent { constructor (props) { super(props) + this.state = { path: props.path, highlighted: null, + constraint: null, files: [], } + + if (props.constraintpath) { + files.getConstraintDevice(props.constraintpath, (error, device) => { + debug('FileSelector:getConstraintDevice', error || device) + this.setState({ constraint: device }) + }) + } } confirmSelection () { @@ -134,13 +144,25 @@ class FileSelector extends React.PureComponent { debug('FileSelector:componentDidUpdate') } + containPath (newPath) { + if (this.state.constraint) { + const isContained = this.state.constraint.mountpoints.some((mount) => { + return !path.relative(mount.path, newPath).startsWith('..') + }) + if (!isContained) { + return '/' + } + } + return newPath + } + navigate (newPath) { debug('FileSelector:navigate', newPath) - this.setState({ path: newPath }) + this.setState({ path: this.containPath(newPath) }) } navigateUp () { - const newPath = path.join( this.state.path, '..' ) + let newPath = this.containPath(path.join(this.state.path, '..')) debug('FileSelector:navigateUp', this.state.path, '->', newPath) this.setState({ path: newPath }) } @@ -254,12 +276,15 @@ class FileSelector extends React.PureComponent {
@@ -282,7 +307,7 @@ class FileSelector extends React.PureComponent { FileSelector.propTypes = { path: propTypes.string, close: propTypes.func, - constraints: propTypes.arrayOf(propTypes.string) + constraintpath: propTypes.string, } module.exports = FileSelector diff --git a/lib/gui/app/components/file-selector/templates/file-selector-modal.tpl.html b/lib/gui/app/components/file-selector/templates/file-selector-modal.tpl.html index 2fc18654..89eb1771 100644 --- a/lib/gui/app/components/file-selector/templates/file-selector-modal.tpl.html +++ b/lib/gui/app/components/file-selector/templates/file-selector-modal.tpl.html @@ -1,4 +1,4 @@ diff --git a/lib/gui/app/models/files.js b/lib/gui/app/models/files.js index 53a8d44d..e7d01d32 100644 --- a/lib/gui/app/models/files.js +++ b/lib/gui/app/models/files.js @@ -18,6 +18,7 @@ const fs = require('fs') const path = require('path') +const drivelist = require('drivelist') /* eslint-disable lodash/prefer-lodash-method */ /* eslint-disable no-undefined */ @@ -70,7 +71,6 @@ class FileEntry { this.isFile = stats.isFile() this.isDirectory = stats.isDirectory() this.size = stats.size - this.stats = stats } } @@ -138,3 +138,30 @@ exports.splitPath = (fullpath, subpaths = []) => { return exports.splitPath(dir, [ base ].concat(subpaths)) } + +/** + * @summary Get constraint path device + * @param {String} pathname - device path + * @param {Function} callback - callback(error, constraintDevice) + * @example + * files.getConstraintDevice('/dev/disk2', (error, device) => { + * // ... + * }) + */ +exports.getConstraintDevice = (pathname, callback) => { + drivelist.list((error, devices) => { + if (error) { + callback() + return + } + + const constraintDevice = devices.find((device) => { + return device.device === pathname || + device.devicePath === pathname + }) + + callback(null, constraintDevice) + }) +} + +exports.FileEntry = FileEntry