diff options
| author | Jules Laplace <julescarbon@gmail.com> | 2018-09-21 22:50:33 +0200 |
|---|---|---|
| committer | Jules Laplace <julescarbon@gmail.com> | 2018-09-21 22:50:33 +0200 |
| commit | 10faab7941b28181c7647ff4e390ab651286bc32 (patch) | |
| tree | b0d71498d2a0649c7180940a38d2fbfa595ca515 /app/client/common | |
| parent | 53ddf1651d649f65d92e12d36c003ff623226e34 (diff) | |
| parent | 15d5cea9d1d94a6893ef1a55a916e68a182e5394 (diff) | |
merge
Diffstat (limited to 'app/client/common')
| -rw-r--r-- | app/client/common/browser.component.js | 89 | ||||
| -rw-r--r-- | app/client/common/currentTask.component.js | 2 | ||||
| -rw-r--r-- | app/client/common/fileList.component.js | 31 | ||||
| -rw-r--r-- | app/client/common/fileViewer.component.js | 57 | ||||
| -rw-r--r-- | app/client/common/folderList.component.js | 6 | ||||
| -rw-r--r-- | app/client/common/index.js | 6 | ||||
| -rw-r--r-- | app/client/common/slider.component.js | 2 | ||||
| -rw-r--r-- | app/client/common/taskList.component.js | 12 | ||||
| -rw-r--r-- | app/client/common/views/new.view.js | 6 |
9 files changed, 187 insertions, 24 deletions
diff --git a/app/client/common/browser.component.js b/app/client/common/browser.component.js new file mode 100644 index 0000000..50b31cf --- /dev/null +++ b/app/client/common/browser.component.js @@ -0,0 +1,89 @@ +import { h, Component } from 'preact' +import { bindActionCreators } from 'redux' +import { connect } from 'react-redux' +import { Route, Link } from 'react-router-dom' + +import { Loading, FileList, FileViewer } from '../common' + +import actions from '../actions' + +class Browser extends Component { + state = { + dir: '/', + files: [], + loading: true + } + componentDidMount() { + this.fetch(this.state.dir) + } + handlePick(file) { + console.log(file) + if (file.dir) { + this.fetch([this.state.dir, file.name].join('/').replace('//','/')) + } else { + this.fetchFile([this.state.dir, file.name].join('/').replace('//','/')) + } + } + fetch(dir) { + console.log('fetch', dir) + const { tool: module } = this.props.app + this.setState({ dir, file: null, loading: true }) + actions.socket.list_directory({ module, dir }).then(files => { + console.log(files) + this.setState({ dir, files, loading: false }) + }) + } + fetchFile(fn) { + console.log('fetch file', fn) + const { tool: module } = this.props.app + this.setState({ file: null, loadingFile: true }) + actions.socket.read_file({ module, fn }).then(file => { + console.log(file) + this.setState({ file, loadingFile: false }) + }) + } + render() { + const { app } = this.props + const { + loading, dir, files, + loadingFile, file, + } = this.state + console.log(this.props, this.state) + return ( + <div className='app browser'> + <h1>{dir}{dir[dir.length-1] !== '/' && '/'}</h1> + {app.tool}<br/> + {loading && <Loading />} + <FileList + files={files} + groupDirectories + parentDirectory={dir !== '/'} + orderBy='name asc' + fields={'name datetime size'} + onClick={(file, e) => { + e.preventDefault() + e.stopPropagation() + console.log('picked a result', file) + this.handlePick(file) + }} + onClickParent={e => { + console.log('navigate up') + this.fetch(this.state.dir.split('/').slice(0, -1).join('/') || '/') + }} + /> + {loadingFile && <Loading />} + {file && <FileViewer file={file} />} + </div> + ) + } +} + +const mapStateToProps = state => ({ + app: state.system.app, +}) + +const mapDispatchToProps = (dispatch, ownProps) => ({ + actions: bindActionCreators({}, dispatch), +}) + +export default connect(mapStateToProps, mapDispatchToProps)(Browser) diff --git a/app/client/common/currentTask.component.js b/app/client/common/currentTask.component.js index 3c71a88..ef976bc 100644 --- a/app/client/common/currentTask.component.js +++ b/app/client/common/currentTask.component.js @@ -31,7 +31,7 @@ function CurrentTask ({ cpu, gpu, processor }) { ? <span>(currently #{epoch})</span> : ""} <br/><br/> - <div class='quiet'>{last_message}</div> + <div className='quiet'>{last_message}</div> </div> ) } diff --git a/app/client/common/fileList.component.js b/app/client/common/fileList.component.js index b71faae..f932274 100644 --- a/app/client/common/fileList.component.js +++ b/app/client/common/fileList.component.js @@ -11,18 +11,24 @@ export const FileList = props => { const { files, fields, sort, title, - linkFiles, onClick, onDelete, + linkFiles, + onClick, onClickParent, onDelete, + groupDirectories, parentDirectory, orderBy='name asc', className='', fileListClassName='filelist', rowClassName='row file' } = props const { mapFn, sortFn } = util.sort.orderByFn(orderBy) - const fileList = (files || []) + let sortedFiles = (files || []) .filter(f => !!f) .map(mapFn) .sort(sortFn) - .map(pair => { + if (groupDirectories) { + const groupedFiles = sortedFiles.reduce((a,b) => { a[b[1].dir].push(b); return a }, { true: [], false: [] }) + sortedFiles = groupedFiles.true.concat(groupedFiles.false) + } + const fileList = sortedFiles.map(pair => { return <FileRow file={pair[1]} fields={fieldSet(fields)} @@ -35,8 +41,8 @@ export const FileList = props => { if (!fileList || !fileList.length) { return ( <div className={'rows ' + className}> - <div class='row heading'> - <h4 class='noFiles'>No files</h4> + <div className='row heading'> + <h4 className='noFiles'>No files</h4> </div> </div> ) @@ -45,12 +51,21 @@ export const FileList = props => { return ( <div className={'rows ' + className}> {title && - <div class='row heading'> + <div className='row heading'> <h3>{title}</h3>} </div> } <div className={'rows ' + fileListClassName}> + {parentDirectory && + <div className={rowClassName + ' parent'}> + <div className="filename" title="Parent Directory"> + <span className='link' onClick={(e) => onClickParent && onClickParent(e)}> + <i>Parent Directory</i> + </span> + </div> + </div> + } {fileList} </div> </div> @@ -83,14 +98,14 @@ export const FileRow = props => { } return ( - <div class={className} key={key}> + <div className={className} key={key}> {fields.has('name') && <div className="filename" title={file.name || file.url}> {file.persisted === false ? <span className='unpersisted'>{name}</span> : (linkFiles && file.url) ? <a target='_blank' onClick={(e) => { if (!(e.metaKey || e.ctrlKey || e.altKey) && onClick) { e.preventDefault(); onClick && onClick(file, e) }}} href={file.url}>{name}</a> - : <span class='link' onClick={(e) => onClick && onClick(file, e)}>{name}</span> + : <span className='link' onClick={(e) => onClick && onClick(file, e)}>{name}</span> } </div> } diff --git a/app/client/common/fileViewer.component.js b/app/client/common/fileViewer.component.js new file mode 100644 index 0000000..bc71f20 --- /dev/null +++ b/app/client/common/fileViewer.component.js @@ -0,0 +1,57 @@ +import { h, Component } from 'preact' + +const image_types = { + 'jpg': 'image/jpeg', + 'jpeg': 'image/jpeg', + 'png': 'image/png', + 'gif': 'image/gif', +} + +const audio_types = { + 'wav': 'audio/wav', + 'mp3': 'audio/mp3', + 'flac': 'audio/flac', + 'aiff': 'audio/aiff', +} + +const video_types = { + 'mp4': 'video/mp4', +} + +export default function FileViewer({ file }) { + const { + error, + name, path, + date, size, + buf, + } = file + if (error) { + return <div className='fileViewer'>{error}</div> + } + if (!buf) { + return <div className='fileViewer'>File empty</div> + } + const ext = name.split('.').slice(-1)[0].toLowerCase() + let tag; + if (ext in image_types) { + tag = <img src={getURLFor(buf, image_types[ext])} /> + } else if (ext in audio_types) { + tag = <audio src={getURLFor(buf, audio_types[ext])} controls autoplay /> + } else if (ext in video_types) { + tag = <video src={getURLFor(buf, audio_types[ext])} controls autoplay /> + } else { + tag = <div className='text'>{ab2str(buf)}</div> + } + return ( + <div className='fileViewer'>{tag}</div> + ) +} + +const getURLFor = (buf, type) => { + const arrayBufferView = new Uint8Array(buf) + const blob = new Blob([arrayBufferView], { type }) + const urlCreator = window.URL || window.webkitURL + return urlCreator.createObjectURL(blob) +} + +const ab2str = buf => String.fromCharCode.apply(null, new Uint8Array(buf)) diff --git a/app/client/common/folderList.component.js b/app/client/common/folderList.component.js index a6c6ae5..91d0bff 100644 --- a/app/client/common/folderList.component.js +++ b/app/client/common/folderList.component.js @@ -12,7 +12,7 @@ export default function FolderList ({ db, path, emptyText, activity }) { if (! db) return null if (db.loading || !db.data) { return ( - <div class='col folderList'> + <div className='col folderList'> <Loading progress={db.progress} /> </div> ) @@ -23,7 +23,7 @@ export default function FolderList ({ db, path, emptyText, activity }) { } if (! folderList.length && emptyText) { return ( - <div class='col folderList'> + <div className='col folderList'> {emptyText} </div> ) @@ -41,7 +41,7 @@ export default function FolderList ({ db, path, emptyText, activity }) { }) return ( - <div class='col folderList'> + <div className='col folderList'> <Group title='Projects'> {folders} </Group> diff --git a/app/client/common/index.js b/app/client/common/index.js index e6baafc..e120597 100644 --- a/app/client/common/index.js +++ b/app/client/common/index.js @@ -1,11 +1,13 @@ import AudioPlayer from './audioPlayer/audioPlayer.component' import AugmentationGrid from './augmentationGrid.component' +import Browser from './browser.component' import Button from './button.component' import ButtonGrid from './buttonGrid.component' import Checkbox from './checkbox.component' import CurrentTask from './currentTask.component' import { FileList, FileRow } from './fileList.component' import FileUpload from './fileUpload.component' +import FileViewer from './fileViewer.component' import FolderList from './folderList.component' import Gallery from './gallery.component' import Group from './group.component' @@ -26,8 +28,8 @@ import * as Views from './views' export { Views, Loading, Progress, Header, AudioPlayer, - FolderList, FileList, FileRow, FileUpload, - Gallery, Player, + FolderList, FileList, FileRow, FileUpload, FileViewer, + Gallery, Player, Browser, Group, ParamGroup, Param, TextInput, NumberInput, Slider, Select, SelectGroup, Button, Checkbox, diff --git a/app/client/common/slider.component.js b/app/client/common/slider.component.js index 7252ca3..9dba730 100644 --- a/app/client/common/slider.component.js +++ b/app/client/common/slider.component.js @@ -81,7 +81,7 @@ class Slider extends Component { text_value = parseFloat(value).toFixed(2) } return ( - <div class='slider param'> + <div className='slider param'> <label> <span>{title || name.replace(/_/g, ' ')}</span> <input type='text' value={text_value} onBlur={this.handleInput} /> diff --git a/app/client/common/taskList.component.js b/app/client/common/taskList.component.js index c1ed38a..272ff80 100644 --- a/app/client/common/taskList.component.js +++ b/app/client/common/taskList.component.js @@ -56,18 +56,18 @@ class TaskList extends Component { dataset_link = label } return ( - <div class='row'> - <div class='activity'>{task.activity} {task.module}</div> - <div class='dataset'>{dataset_link}</div> + <div className='row'> + <div className='activity'>{task.activity} {task.module}</div> + <div className='dataset'>{dataset_link}</div> <div className={"age " + util.carbon_date(task.updated_at)}>{util.get_age(task.updated_at)}</div> - <div class='options'> - <span class='destroy' onClick={() => this.handleDestroy(task)}>x</span> + <div className='options'> + <span className='destroy' onClick={() => this.handleDestroy(task)}>x</span> </div> </div> ) }) return ( - <div class='tasklist rows'> + <div className='tasklist rows'> {taskList} </div> ) diff --git a/app/client/common/views/new.view.js b/app/client/common/views/new.view.js index a6ab3b1..a417bfc 100644 --- a/app/client/common/views/new.view.js +++ b/app/client/common/views/new.view.js @@ -22,11 +22,11 @@ export default class NewView extends Component { render(){ const { module, history, db, path } = this.props return ( - <div class={'app new-view ' + module.name}> - <div class='heading'> + <div className={'app new-view ' + module.name}> + <div className='heading'> <h1>{module.displayName || module.name}</h1> </div> - <div class='col narrow'> + <div className='col narrow'> <NewDatasetForm module={module} history={history} |
