Remove experimental file picker

Change-type: patch
This commit is contained in:
Alexis Svinartchouk 2019-12-04 15:36:36 +01:00 committed by Lorenzo Alberto Maria Ambrosi
parent 330405ae42
commit 07fc7af911
16 changed files with 12 additions and 1201 deletions

View File

@ -88,7 +88,6 @@ const app = angular.module('Etcher', [
// Components
require('./components/svg-icon'),
require('./components/safe-webview'),
require('./components/file-selector'),
// Pages
require('./pages/main/main'),

View File

@ -1,72 +0,0 @@
/*
* Copyright 2018 resin.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict'
const _ = require('lodash')
const os = require('os')
const settings = require('../../../models/settings')
const utils = require('../../../../../shared/utils')
const angular = require('angular')
/* eslint-disable lodash/prefer-lodash-method */
module.exports = function (
$uibModalInstance
) {
/**
* @summary Close the modal
* @function
* @public
*
* @example
* FileSelectorController.close();
*/
this.close = () => {
$uibModalInstance.close()
}
/**
* @summary Folder to constrain the file picker to
* @function
* @public
*
* @returns {String} - folder to constrain by
*
* @example
* FileSelectorController.getFolderConstraint()
*/
this.getFolderConstraint = utils.memoize(() => {
return settings.has('fileBrowserConstraintPath')
? settings.get('fileBrowserConstraintPath')
: ''
}, angular.equals)
/**
* @summary Get initial path
* @function
* @public
*
* @returns {String} - path
*
* @example
* <file-selector path="FileSelectorController.getPath()"></file-selector>
*/
this.getPath = () => {
const constraintFolderPath = this.getFolderConstraint()
return _.isEmpty(constraintFolderPath) ? os.homedir() : constraintFolderPath
}
}

View File

@ -1,45 +0,0 @@
/*
* Copyright 2018 resin.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict'
/**
* @summary Color scheme
* @constant
* @private
*/
const colors = {
primary: {
color: '#3a3c41',
background: '#ffffff',
subColor: '#ababab',
faded: '#c3c4c6'
},
secondary: {
color: '#1c1d1e',
background: '#ebeff4',
title: '#b3b6b9'
},
highlight: {
color: 'white',
background: '#2297de'
},
soft: {
color: '#4d5056'
}
}
module.exports = colors

View File

@ -1,321 +0,0 @@
/*
* Copyright 2018 resin.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict'
const React = require('react')
const propTypes = require('prop-types')
const styled = require('styled-components').default
const rendition = require('rendition')
const colors = require('./colors')
const prettyBytes = require('pretty-bytes')
const files = require('../../../models/files')
const middleEllipsis = require('../../../utils/middle-ellipsis')
const supportedFormats = require('../../../../../shared/supported-formats')
const debug = require('debug')('etcher:gui:file-selector')
/**
* @summary Character limit of a filename before a middle-ellipsis is added
* @constant
* @private
*/
const FILENAME_CHAR_LIMIT = 20
/**
* @summary Pattern to match all supported formats for highlighting
* @constant
* @private
*/
const SUPPORTED_FORMATS_PATTERN = new RegExp(`^\\.(${supportedFormats.getAllExtensions().join('|')})$`, 'i')
/**
* @summary Flex styled component
* @function
* @type {ReactElement}
*/
const Flex = styled.div`
display: flex;
flex: ${ props => props.flex };
flex-direction: ${ props => props.direction };
justify-content: ${ props => props.justifyContent };
align-items: ${ props => props.alignItems };
flex-wrap: ${ props => props.wrap };
flex-grow: ${ props => props.grow };
`
/**
* @summary Anchor flex styled component
* @function
* @type {ReactElement}
*/
const ClickableFlex = styled.a`
display: flex;
flex: ${ props => props.flex };
flex-direction: ${ props => props.direction };
justify-content: ${ props => props.justifyContent };
align-items: ${ props => props.alignItems };
flex-wrap: ${ props => props.wrap };
flex-grow: ${ props => props.grow };
`
/**
* @summary FileList scroll wrapper element
* @class
* @type {ReactElement}
*/
class UnstyledFileListWrap extends React.PureComponent {
constructor (props) {
super(props)
this.scrollElem = null
}
render () {
return (
<Flex className={ this.props.className }
ref={ ::this.setScrollElem }
wrap="wrap">
{ this.props.children }
</Flex>
)
}
setScrollElem (element) {
this.scrollElem = element
}
componentDidUpdate (prevProps) {
if (this.scrollElem) {
this.scrollElem.scrollTop = 0
}
}
}
/**
* @summary FileList scroll wrapper element
* @class
* @type {StyledComponent}
*/
const FileListWrap = styled(UnstyledFileListWrap)`
overflow-x: hidden;
overflow-y: auto;
padding: 0 20px;
`
/**
* @summary File element
* @class
* @type {ReactElement}
*/
class UnstyledFile extends React.PureComponent {
static getFileIconClass (file) {
return file.isDirectory
? 'fas fa-folder'
: 'fas fa-file-alt'
}
onHighlight (event) {
event.preventDefault()
this.props.onHighlight(this.props.file)
}
onSelect (event) {
event.preventDefault()
this.props.onSelect(this.props.file)
}
render () {
const file = this.props.file
return (
<ClickableFlex
data-path={ file.path }
href={ `file://${file.path}` }
direction="column"
alignItems="stretch"
className={ this.props.className }
onClick={ ::this.onHighlight }
onDoubleClick={ ::this.onSelect }>
<span className={ UnstyledFile.getFileIconClass(file) } />
<span>{ middleEllipsis(file.basename, FILENAME_CHAR_LIMIT) }</span>
<div>{ file.isDirectory ? '' : prettyBytes(file.size || 0) }</div>
</ClickableFlex>
)
}
}
/**
* @summary File element
* @class
* @type {StyledComponent}
*/
const File = styled(UnstyledFile)`
width: 100px;
min-height: 100px;
max-height: 128px;
margin: 5px 10px;
padding: 5px;
background-color: none;
transition: 0.05s background-color ease-out;
color: ${ colors.primary.color };
cursor: pointer;
border-radius: 5px;
word-break: break-word;
> span:first-of-type {
align-self: center;
line-height: 1;
margin-bottom: 6px;
font-size: 48px;
color: ${ props => props.disabled ? colors.primary.faded : colors.soft.color };
}
> span:last-of-type {
display: flex;
justify-content: center;
text-align: center;
font-size: 16px;
}
> div:last-child {
background-color: none;
color: ${ colors.primary.subColor };
text-align: center;
font-size: 12px;
}
:hover, :visited {
color: ${ colors.primary.color };
}
:focus,
:active {
color: ${ colors.highlight.color };
background-color: ${ colors.highlight.background };
}
:focus > span:first-of-type,
:active > span:first-of-type {
color: ${ colors.highlight.color };
}
:focus > div:last-child,
:active > div:last-child {
color: ${ colors.highlight.color };
}
`
/**
* @summary FileList element
* @class
* @type {ReactElement}
*/
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 })
})
})
}
componentDidMount () {
process.nextTick(() => {
this.readdir(this.state.path)
})
}
onHighlight (file) {
debug('FileList:onHighlight', file)
this.props.onHighlight(file)
}
onSelect (file) {
debug('FileList:onSelect', file.path, file.isDirectory)
this.props.onSelect(file)
}
shouldComponentUpdate (nextProps, nextState) {
const shouldUpdate = (this.state.files !== nextState.files)
debug('FileList:shouldComponentUpdate', shouldUpdate)
if (this.props.path !== nextProps.path || this.props.constraint !== nextProps.constraint) {
process.nextTick(() => {
this.readdir(nextProps.path)
})
}
return shouldUpdate
}
static isSelectable (file) {
return file.isDirectory || !file.ext ||
SUPPORTED_FORMATS_PATTERN.test(file.ext)
}
render () {
return (
<FileListWrap wrap="wrap">
{
this.state.files.map((file) => {
return (
<File key={ file.path }
file={ file }
disabled={ !FileList.isSelectable(file) }
onSelect={ ::this.onSelect }
onHighlight={ ::this.onHighlight }/>
)
})
}
</FileListWrap>
)
}
}
module.exports = FileList

View File

@ -1,358 +0,0 @@
/*
* Copyright 2018 resin.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict'
const path = require('path')
const sdk = require('etcher-sdk')
const Bluebird = require('bluebird')
const React = require('react')
const propTypes = require('prop-types')
const styled = require('styled-components').default
const rendition = require('rendition')
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 store = require('../../../models/store')
const osDialog = require('../../../os/dialog')
const exceptionReporter = require('../../../modules/exception-reporter')
const messages = require('../../../../../shared/messages')
const errors = require('../../../../../shared/errors')
const supportedFormats = require('../../../../../shared/supported-formats')
const analytics = require('../../../modules/analytics')
const debug = require('debug')('etcher:gui:file-selector')
/**
* @summary Flex styled component
* @function
* @type {ReactElement}
*/
const Flex = styled.div`
display: flex;
flex: ${ props => props.flex };
flex-direction: ${ props => props.direction };
justify-content: ${ props => props.justifyContent };
align-items: ${ props => props.alignItems };
flex-wrap: ${ props => props.wrap };
flex-grow: ${ props => props.grow };
overflow: ${ props => props.overflow };
`
const Header = styled(Flex) `
padding: 10px 15px 0;
border-bottom: 1px solid ${ colors.primary.faded };
> * {
margin: 5px;
}
`
const Main = styled(Flex) ``
const Footer = styled(Flex) `
padding: 10px;
flex: 0 0 auto;
border-top: 1px solid ${ colors.primary.faded };
> * {
margin: 0 10px;
}
> button {
flex-grow: 0;
flex-shrink: 0;
}
`
class UnstyledFilePath extends React.PureComponent {
render () {
return (
<div className={ this.props.className }>
<span>{
this.props.file && !this.props.file.isDirectory
? this.props.file.basename
: ''
}</span>
</div>
)
}
}
const FilePath = styled(UnstyledFilePath)`
display: flex;
flex-grow: 1;
align-items: center;
overflow: hidden;
> span {
font-size: 16px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
`
class FileSelector extends React.PureComponent {
constructor (props) {
super(props)
this.state = {
path: props.path,
highlighted: null,
constraint: null,
files: [],
}
}
componentDidMount() {
if (this.props.constraintpath) {
const device = files.getConstraintDevice(this.props.constraintpath)
debug('FileSelector:getConstraintDevice', device)
if (device !== undefined) {
this.setState({ constraint: device.drive })
}
}
}
confirmSelection () {
if (this.state.highlighted) {
this.selectFile(this.state.highlighted)
}
}
close () {
this.props.close()
}
componentDidUpdate () {
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: this.containPath(newPath) })
}
navigateUp () {
let newPath = this.containPath(path.join(this.state.path, '..'))
debug('FileSelector:navigateUp', this.state.path, '->', newPath)
this.setState({ path: newPath })
}
selectImage (image) {
debug('FileSelector:selectImage', image)
if (!supportedFormats.isSupportedImage(image.path)) {
const invalidImageError = errors.createUserError({
title: 'Invalid image',
description: messages.error.invalidImage(image.path)
})
osDialog.showError(invalidImageError)
analytics.logEvent('Invalid image', {
image,
applicationSessionUuid: store.getState().toJS().applicationSessionUuid,
flashingWorkflowUuid: store.getState().toJS().flashingWorkflowUuid
})
return Bluebird.resolve()
}
return Bluebird.try(() => {
let message = null
if (supportedFormats.looksLikeWindowsImage(image.path)) {
analytics.logEvent('Possibly Windows image', {
image,
applicationSessionUuid: store.getState().toJS().applicationSessionUuid,
flashingWorkflowUuid: store.getState().toJS().flashingWorkflowUuid
})
message = messages.warning.looksLikeWindowsImage()
} else if (!image.hasMBR) {
analytics.logEvent('Missing partition table', {
image,
applicationSessionUuid: store.getState().toJS().applicationSessionUuid,
flashingWorkflowUuid: store.getState().toJS().flashingWorkflowUuid
})
message = messages.warning.missingPartitionTable()
}
if (message) {
// TODO: `Continue` should be on a red background (dangerous action) instead of `Change`.
// We want `X` to act as `Continue`, that's why `Continue` is the `rejectionLabel`
return osDialog.showWarning({
confirmationLabel: 'Change',
rejectionLabel: 'Continue',
title: 'Warning',
description: message
})
}
return false
}).then((shouldChange) => {
if (shouldChange) {
return
}
selectionState.selectImage(image)
this.close()
// An easy way so we can quickly identify if we're making use of
// certain features without printing pages of text to DevTools.
image.logo = Boolean(image.logo)
image.blockMap = Boolean(image.blockMap)
analytics.logEvent('Select image', {
image,
applicationSessionUuid: store.getState().toJS().applicationSessionUuid,
flashingWorkflowUuid: store.getState().toJS().flashingWorkflowUuid
})
}).catch(exceptionReporter.report)
}
selectFile (file) {
debug('FileSelector:selectFile', file)
if (file.isDirectory) {
this.navigate(file.path)
return
}
if (!supportedFormats.isSupportedImage(file.path)) {
const invalidImageError = errors.createUserError({
title: 'Invalid image',
description: messages.error.invalidImage(file.path)
})
osDialog.showError(invalidImageError)
analytics.logEvent('Invalid image', { path: file.path })
return
}
debug('FileSelector:getImageMetadata', file)
const source = new sdk.sourceDestination.File(file.path, sdk.sourceDestination.File.OpenFlags.Read)
source.getInnerSource()
.then((innerSource) => {
return innerSource.getMetadata()
.then((imageMetadata) => {
debug('FileSelector:getImageMetadata', imageMetadata)
imageMetadata.path = file.path
imageMetadata.extension = path.extname(file.path).slice(1)
return innerSource.getPartitionTable()
.then((partitionTable) => {
if (partitionTable !== undefined) {
imageMetadata.hasMBR = true
imageMetadata.partitions = partitionTable.partitions
}
return this.selectImage(imageMetadata)
})
})
})
.catch((error) => {
debug('FileSelector:getImageMetadata', error)
const imageError = errors.createUserError({
title: 'Error opening image',
description: messages.error.openImage(path.basename(file.path), error.message)
})
osDialog.showError(imageError)
analytics.logException(error)
})
}
onHighlight (file) {
this.setState({ highlighted: file })
}
render () {
const styles = {
display: 'flex',
height: 'calc(100vh - 20px)',
}
return (
<rendition.Provider style={ styles }>
{/*<RecentFiles flex="0 0 auto"
selectFile={ ::this.selectFile }
navigate={ ::this.navigate } />*/}
<Flex direction="column" grow="1" overflow="auto">
<Header flex="0 0 auto" alignItems="baseline">
<rendition.Button
bg={ colors.secondary.background }
color={ colors.primary.color }
onClick={ ::this.navigateUp }>
<span className="fas fa-angle-left" />
&nbsp;Back
</rendition.Button>
<span className="fas fa-hdd" />
<Breadcrumbs
path={ this.state.path }
navigate={ ::this.navigate }
constraintPath={ this.props.constraintpath }
constraint={ this.state.constraint }
/>
</Header>
<Main flex="1">
<Flex direction="column" grow="1">
<FileList path={ this.state.path }
constraintPath={ this.props.constraintpath }
constraint={ this.state.constraint }
onHighlight={ ::this.onHighlight }
onSelect={ ::this.selectFile }></FileList>
</Flex>
</Main>
<Footer justifyContent="flex-end">
<FilePath file={ this.state.highlighted }></FilePath>
<rendition.Button onClick={ ::this.close }>Cancel</rendition.Button>
<rendition.Button
primary
onClick={ ::this.confirmSelection }>
Select file
</rendition.Button>
</Footer>
</Flex>
</rendition.Provider>
)
}
}
FileSelector.propTypes = {
path: propTypes.string,
close: propTypes.func,
constraintpath: propTypes.string,
}
module.exports = FileSelector

View File

@ -1,119 +0,0 @@
/*
* Copyright 2018 resin.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict'
const path = require('path')
const React = require('react')
const propTypes = require('prop-types')
const styled = require('styled-components').default
const rendition = require('rendition')
const middleEllipsis = require('../../../utils/middle-ellipsis')
/**
* @summary How many directories to show with the breadcrumbs
* @type {Number}
* @constant
* @private
*/
const MAX_DIR_CRUMBS = 3
/**
* @summary Character limit of a filename before a middle-ellipsis is added
* @constant
* @private
*/
const FILENAME_CHAR_LIMIT_SHORT = 15
function splitComponents(dirname, root) {
const components = []
let basename = null
root = root || path.parse(dirname).root
while( dirname !== root ) {
basename = path.basename(dirname)
components.unshift({
path: dirname,
basename: basename,
name: basename
})
dirname = path.join( dirname, '..' )
}
if (components.length < MAX_DIR_CRUMBS) {
components.unshift({
path: root,
basename: root,
name: 'Root'
})
}
return components
}
class Crumb extends React.PureComponent {
constructor (props) {
super(props)
}
render () {
return (
<rendition.Button
onClick={ ::this.navigate }
plain={ true }>
<rendition.Txt bold={ this.props.bold }>
{ middleEllipsis(this.props.dir.name, FILENAME_CHAR_LIMIT_SHORT) }
</rendition.Txt>
</rendition.Button>
)
}
navigate () {
this.props.navigate(this.props.dir.path)
}
}
class UnstyledBreadcrumbs extends React.PureComponent {
render () {
const components = splitComponents(this.props.path).slice(-MAX_DIR_CRUMBS)
return (
<div className={ this.props.className }>
{
components.map((dir, index) => {
return (
<Crumb
key={ dir.path }
bold={ index === components.length - 1 }
dir={ dir }
navigate={ ::this.props.navigate }
/>
)
})
}
</div>
)
}
}
const Breadcrumbs = styled(UnstyledBreadcrumbs)`
font-size: 18px;
& > button:not(:last-child)::after {
content: '/';
margin: 9px;
}
`
module.exports = Breadcrumbs

View File

@ -1,125 +0,0 @@
/*
* Copyright 2018 resin.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict'
const React = require('react')
const propTypes = require('prop-types')
const styled = require('styled-components').default
const rendition = require('rendition')
const colors = require('./colors')
const middleEllipsis = require('../../../utils/middle-ellipsis')
/**
* @summary Flex styled component
* @function
* @type {ReactElement}
*/
const Flex = styled.div`
display: flex;
flex: ${ props => props.flex };
flex-direction: ${ props => props.direction };
justify-content: ${ props => props.justifyContent };
align-items: ${ props => props.alignItems };
flex-wrap: ${ props => props.wrap };
flex-grow: ${ props => props.grow };
`
class RecentFileLink extends React.PureComponent {
constructor (props) {
super(props)
}
render () {
const file = this.props.file
return (
<rendition.Button
onClick={ ::this.select }
plain={ true }>
{ middleEllipsis(file.name, FILENAME_CHAR_LIMIT_SHORT) }
</rendition.Button>
)
}
select () {
this.props.onSelect(this.props.file)
}
}
class UnstyledRecentFiles extends React.PureComponent {
constructor(props) {
super(props)
this.state = {
recent: [],
favorites: []
}
}
render () {
return (
<Flex className={ this.props.className }>
<h5>Recent</h5>
{
this.state.recent.map((file) => {
<RecentFileLink key={ file.path }
file={ file }
onSelect={ this.props.selectFile }/>
})
}
<h5>Favorite</h5>
{
this.state.favorites.map((file) => {
<RecentFileLink key={ file.path }
file={ file }
onSelect={ this.props.navigate }/>
})
}
</Flex>
)
}
}
const RecentFiles = styled(UnstyledRecentFiles)`
display: flex;
flex: 0 0 auto;
flex-direction: column;
align-items: flex-start;
width: 130px;
background-color: ${ colors.secondary.background };
padding: 20px;
color: ${ colors.secondary.color };
> h5 {
color: ${ colors.secondary.title };
font-size: 11px;
font-weight: 500;
text-transform: uppercase;
margin-bottom: 15px;
}
> h5:last-of-type {
margin-top: 20px;
}
> button {
margin-bottom: 10px;
text-align: start;
font-size: 16px;
}
`
module.exports = RecentFiles

View File

@ -1,37 +0,0 @@
/*
* Copyright 2018 resin.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict'
/* eslint-disable jsdoc/require-example */
/**
* @module Etcher.Components.SVGIcon
*/
const angular = require('angular')
const react2angular = require('react2angular').react2angular
const MODULE_NAME = 'Etcher.Components.FileSelector'
const angularFileSelector = angular.module(MODULE_NAME, [
require('../modal/modal')
])
angularFileSelector.component('fileSelector', react2angular(require('./file-selector/file-selector.jsx')))
angularFileSelector.controller('FileSelectorController', require('./controllers/file-selector'))
angularFileSelector.service('FileSelectorService', require('./services/file-selector'))
module.exports = MODULE_NAME

View File

@ -1,53 +0,0 @@
/*
* Copyright 2018 resin.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict'
module.exports = function (ModalService, $q) {
let modal = null
/**
* @summary Open the file selector widget
* @function
* @public
*
* @example
* DriveSelectorService.open()
*/
this.open = () => {
modal = ModalService.open({
name: 'file-selector',
template: require('../templates/file-selector-modal.tpl.html'),
controller: 'FileSelectorController as selector',
size: 'file-selector-modal'
})
}
/**
* @summary Close the file selector widget
* @function
* @public
*
* @example
* DriveSelectorService.close()
*/
this.close = () => {
if (modal) {
modal.close()
}
modal = null
}
}

View File

@ -1,23 +0,0 @@
/*
* Copyright 2018 resin.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
.modal-file-selector-modal {
width: calc(100vw - 10px);
> .modal-content {
height: calc(100vh - 20px);
}
}

View File

@ -1,4 +0,0 @@
<file-selector
constraintpath="selector.getFolderConstraint()"
path="selector.getPath()"
close="selector.close"></file-selector>

View File

@ -255,13 +255,6 @@ class ImageSelector extends React.Component {
flashingWorkflowUuid: store.getState().toJS().flashingWorkflowUuid
})
if (settings.get('experimentalFilePicker')) {
const {
FileSelectorService
} = this.props
FileSelectorService.open()
} else {
osDialog.selectImage().then((imagePath) => {
// Avoid analytics and selection state changes
// if no file was resolved from the dialog.
@ -276,7 +269,6 @@ class ImageSelector extends React.Component {
this.selectImageByPath(imagePath)
}).catch(exceptionReporter.report)
}
}
handleOnDrop (acceptedFiles) {
const [ file ] = acceptedFiles

View File

@ -33,7 +33,6 @@ ImageSelector.component(
react2angular(require('./image-selector.jsx')),
[],
[
'FileSelectorService',
'WarningModalService'
]
)

View File

@ -31,7 +31,6 @@ const MainPage = angular.module(MODULE_NAME, [
require('../../components/drive-selector/drive-selector'),
require('../../components/image-selector'),
require('../../components/file-selector'),
require('../../components/featured-project'),
require('../../components/reduced-flashing-infos'),
require('../../components/flash-another'),

View File

@ -34,7 +34,6 @@ $disabled-opacity: 0.2;
@import "../components/modal/styles/modal";
@import "../components/drive-selector/styles/drive-selector";
@import "../components/svg-icon/styles/svg-icon";
@import "../components/file-selector/styles/file-selector";
@import "../pages/main/styles/main";
@import "../pages/finish/styles/finish";

View File

@ -6286,26 +6286,6 @@ svg-icon {
width: 100%;
height: 100%; }
/*
* Copyright 2018 resin.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
.modal-file-selector-modal {
width: calc(100vw - 10px); }
.modal-file-selector-modal > .modal-content {
height: calc(100vh - 20px); }
/*
* Copyright 2016 resin.io
*