From d41070c7b00fafc974a1a6e7b6d1b42391fa57ed Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Fri, 21 Jul 2017 04:48:52 +0200 Subject: all async paths working --- client/actions/index.js | 4 + client/components/Browser/Files/FileListView.jsx | 4 +- .../components/Browser/Folders/FolderListView.jsx | 4 +- client/components/Tasks/TaskListView.jsx | 41 +++- client/components/UI/AudioPlayerView.jsx | 19 +- client/components/UI/Link.jsx | 8 +- client/containers/fileLink.js | 16 +- client/containers/taskContentLink.js | 1 + client/containers/taskList.js | 9 +- client/containers/taskStyleLink.js | 1 + client/index.jsx | 2 +- client/reducers/folders.js | 2 +- client/reducers/tasks.js | 14 +- client/socket.js | 13 +- client/vendor/format.js | 210 +++++++++++++++++++++ client/vendor/paths.js | 18 ++ 16 files changed, 319 insertions(+), 47 deletions(-) create mode 100644 client/vendor/format.js create mode 100644 client/vendor/paths.js (limited to 'client') diff --git a/client/actions/index.js b/client/actions/index.js index 6a552ac..4263c3b 100644 --- a/client/actions/index.js +++ b/client/actions/index.js @@ -41,6 +41,10 @@ export const loadTasks = (tasks) => ({ type: 'LOAD_TASKS', tasks, }) +export const cancelTask = (task) => ({ + type: 'CANCEL_TASK', + task, +}) /* folders */ diff --git a/client/components/Browser/Files/FileListView.jsx b/client/components/Browser/Files/FileListView.jsx index 4615cf7..df59a1d 100644 --- a/client/components/Browser/Files/FileListView.jsx +++ b/client/components/Browser/Files/FileListView.jsx @@ -21,7 +21,7 @@ export default function FileListView (props) { return (
{file.name} - {file.processed ? file.mime : 'working...'} + {file.processed ? file.mime : '(waiting)'} {file.duration ? (file.duration.toFixed(1) + 's') : ''} content @@ -39,7 +39,7 @@ export default function FileListView (props) {
-
+
{files}
diff --git a/client/components/Browser/Folders/FolderListView.jsx b/client/components/Browser/Folders/FolderListView.jsx index 0a0d0e2..e9d2d44 100644 --- a/client/components/Browser/Folders/FolderListView.jsx +++ b/client/components/Browser/Folders/FolderListView.jsx @@ -3,7 +3,7 @@ import { h, Component } from 'preact' export default function FolderListView (props) { const folders = props.folders.map( (folder, i) => (
props.openFolder(folder)}> - {folder.name} + {folder.name}
)) @@ -15,7 +15,7 @@ export default function FolderListView (props) { -
+
{folders}
diff --git a/client/components/Tasks/TaskListView.jsx b/client/components/Tasks/TaskListView.jsx index 47be794..b93ecc3 100644 --- a/client/components/Tasks/TaskListView.jsx +++ b/client/components/Tasks/TaskListView.jsx @@ -1,24 +1,51 @@ import { h, Component } from 'preact' +import format from '../../vendor/format.js' import FileLink from '../../containers/fileLink.js' export default function TaskListView (props) { const tasks = (props.tasks || []).map( (task, i) => { - return ( -
- {task.id} - {task.created_at} + const created_at = format.verboseDate(task.created_at) + let files = [] + let cancel + if (task.content_file) { + files.push( + ) + } + if (task.style_file) { + files.push( - α={task.alpha} - + ) + } + if (! task.output_file && ! task.processing) { + cancel = ( + props.cancelTask(task)}>x + ) + } + const completed = task.completed ? 'completed' : '' + let filename = task.output_file ? task.output_file.name : + task.processing ? '(processing)' : '(waiting)' + return ( +
+
+ {created_at.date} + {created_at.time} + {filename} + {cancel} +
+
+ α={task.alpha} + {files} +
) // {task.result_file.name} }) return ( -
+
{tasks}
) } + diff --git a/client/components/UI/AudioPlayerView.jsx b/client/components/UI/AudioPlayerView.jsx index d2c9982..e715c27 100644 --- a/client/components/UI/AudioPlayerView.jsx +++ b/client/components/UI/AudioPlayerView.jsx @@ -1,19 +1,21 @@ import { h, Component } from 'preact' - +import { pngpath, mp3path } from '../../vendor/paths' const audio = document.createElement('audio') export default function AudioPlayerView (props) { if (props.file) { document.body.style.backgroundImage = 'url(' + pngpath(props.file) + ')' audio.src = mp3path(props.file) + audio.currentTime = 0 audio.play() return ( -
+
audio.paused ? audio.play() : audio.pause()}> Playing {props.file.name}
) } else { + audio.pause() return (
Not Playing @@ -21,16 +23,3 @@ export default function AudioPlayerView (props) { ) } } - -function filepath (file) { - return '/data/' + file.folder_id + '/' + encodeURIComponent(file.name) -} -function mp3path (file) { - if (file.mime !== 'audio/mp3') { - return filepath(file) + '.mp3' - } - return filepath(file) -} -function pngpath (file) { - return filepath(file) + '.png' -} diff --git a/client/components/UI/Link.jsx b/client/components/UI/Link.jsx index d71582b..b4d2d28 100644 --- a/client/components/UI/Link.jsx +++ b/client/components/UI/Link.jsx @@ -2,15 +2,15 @@ import { h, Component } from 'preact' import React from 'react' // import PropTypes from 'prop-types' -const Link = ({ active, children, onClick, disabled }) => { +const Link = ({ href, active, children, onClick, selected, disabled }) => { if (active) { return {children} } - const className = disabled ? 'disabled' : '' - + const className = disabled ? 'disabled' : + selected ? 'selected' : '' return ( // eslint-disable-next-line - { e.preventDefault() diff --git a/client/containers/fileLink.js b/client/containers/fileLink.js index 92933cf..22834d8 100644 --- a/client/containers/fileLink.js +++ b/client/containers/fileLink.js @@ -1,17 +1,27 @@ import { connect } from 'react-redux' import { audioPlayFile } from '../actions' +import { filepath } from '../vendor/paths' import Link from '../components/UI/Link.jsx' const mapStateToProps = (state, ownProps) => ({ - children: ownProps.children || ownProps.file ? ownProps.file.name : "(~)", - disabled: ownProps.disabled || ! ownProps.file + href: ownProps.file ? filepath(ownProps.file) : '#', + children: ownProps.children || (ownProps.file ? ownProps.file.name : "(~)"), + disabled: ownProps.disabled || ! ownProps.file, + selected: ownProps.file && state.audioPlayer.file && state.audioPlayer.file.id == ownProps.file.id }) const mapDispatchToProps = (dispatch, ownProps) => ({ onClick: () => { switch (ownProps.file.type) { case 'audio': - dispatch(audioPlayFile(ownProps.file)) + let file = ownProps.file + dispatch(audioPlayFile(null)) + setTimeout(() => { + dispatch(audioPlayFile(ownProps.file)) + }, 10) + break + case 'image': + // document.body.style.backgroundImage = break } } diff --git a/client/containers/taskContentLink.js b/client/containers/taskContentLink.js index bb8ae37..524e6aa 100644 --- a/client/containers/taskContentLink.js +++ b/client/containers/taskContentLink.js @@ -3,6 +3,7 @@ import { setContent } from '../actions' import Link from '../components/UI/Link.jsx' const mapStateToProps = (state, ownProps) => ({ + selected: state.currentTask.content == ownProps.file }) const mapDispatchToProps = (dispatch, ownProps) => ({ diff --git a/client/containers/taskList.js b/client/containers/taskList.js index f4a5a1d..b341e91 100644 --- a/client/containers/taskList.js +++ b/client/containers/taskList.js @@ -1,11 +1,14 @@ import { connect } from 'react-redux' -// import {} from '../actions' +import { cancelTask } from '../actions' import TaskListView from '../components/Tasks/TaskListView.jsx' const mapStateToProps = (state) => ({ tasks: state.tasks }) -const mapDispatchToProps = { -} +const mapDispatchToProps = (dispatch) => ({ + cancelTask: (task) => { + dispatch(cancelTask(task)) + } +}) const TaskList = connect( mapStateToProps, diff --git a/client/containers/taskStyleLink.js b/client/containers/taskStyleLink.js index 7ec5ce5..6157e00 100644 --- a/client/containers/taskStyleLink.js +++ b/client/containers/taskStyleLink.js @@ -3,6 +3,7 @@ import { setStyle } from '../actions' import Link from '../components/UI/Link.jsx' const mapStateToProps = (state, ownProps) => ({ + selected: state.currentTask.style == ownProps.file }) const mapDispatchToProps = (dispatch, ownProps) => ({ diff --git a/client/index.jsx b/client/index.jsx index 1a8577e..4b95736 100644 --- a/client/index.jsx +++ b/client/index.jsx @@ -14,7 +14,7 @@ client.folder.index().then( folders => { store.dispatch( loadOpenFolders(openFolders) ) openFolders.forEach( folder_id => { client.file.index({ folder_id }).then( files => { - store.dispatch(loadFiles(files)) + store.dispatch( loadFiles(files) ) }) }) } diff --git a/client/reducers/folders.js b/client/reducers/folders.js index e77c954..6731758 100644 --- a/client/reducers/folders.js +++ b/client/reducers/folders.js @@ -44,7 +44,7 @@ const folders = (state = {}, action) => { folder = action.folder folder_id = folder.id if (openFolders.indexOf(folder.id) === -1) { - openFolders = openFolders.concat(folder.id) + openFolders = [folder.id].concat(openFolders || []) localStorage['openFolders'] = JSON.stringify(openFolders) } filesAreLoaded = state.folders.some( (folder) => { diff --git a/client/reducers/tasks.js b/client/reducers/tasks.js index 9c2b0b4..904c368 100644 --- a/client/reducers/tasks.js +++ b/client/reducers/tasks.js @@ -1,6 +1,8 @@ import client from '../client' const tasks = (state = [], action) => { + let updated_tasks; + switch (action.type) { case 'LOAD_TASKS': return action.tasks @@ -9,13 +11,17 @@ const tasks = (state = [], action) => { return [action.task].concat(state) case 'UPDATE_TASK': - const updated_tasks = state.map(task => { - if (task.id == id) { - return task + updated_tasks = state.map(task => { + if (task.id === action.task.id) { + return action.task } - return id + return task }) return updated_tasks + + case 'CANCEL_TASK': + client.task.destroy(action.task) + return state.filter(task => task !== action.task) default: return state diff --git a/client/socket.js b/client/socket.js index d94a968..9c35af5 100644 --- a/client/socket.js +++ b/client/socket.js @@ -1,4 +1,4 @@ -import { updateFile } from './actions' +import { updateFile, updateTask, addFile } from './actions' import store from './store' const socket = io(window.location.origin) @@ -9,13 +9,16 @@ socket.on('connect', (data) => { socket.on('worker', (data) => { console.log('worker connected', data) }) -socket.on('processed', (data) => { - console.log('processed', data) +socket.on('updateFile', (data) => { + console.log('updateFile', data) store.dispatch(updateFile(data.file)) }) -socket.on('completed', (data) => { - console.log('completed', data) +socket.on('updateTask', (data) => { + console.log('updateTask', data) store.dispatch(updateTask(data.task)) + if (data.task.output_file) { + store.dispatch(addFile(data.task.output_file)) + } }) export default socket diff --git a/client/vendor/format.js b/client/vendor/format.js new file mode 100644 index 0000000..1e5836e --- /dev/null +++ b/client/vendor/format.js @@ -0,0 +1,210 @@ +export default { + commatize, + privacyDot, + shortMonths, + verboseDate, + carbonDate, + hushViews, + hushSize, + hushNull, + courtesyS, + getRevision, + getAge, + tidyURLs, + getDomain, +} + +function commatize (n) { + var nums = [], i, counter = 0, r = Math.floor + if (n > 1024) { + n /= 1024 + nums.unshift(r((n * 10) % 10)) + nums.unshift(".") + } + do { + i = n % 10 + n = r(n / 10) + if (n && ! (++counter % 3)) + { i = ' ' + r(i) } + nums.unshift(r(i)) + } + while (n) + return nums.join("") +} + +function privacyDot (p) { + if (! p) return "·" + else return "·:" +} + +const shortMonths = "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" ") +function verboseDate (dateStr, pad_hours) { + const dateObj = new Date(dateStr) + let d = dateObj.getDate() + let m = dateObj.getMinutes() + let h = dateObj.getHours() + let meridian + + if (h == 0) { + h = 12 + meridian = " am" + } + else if (h == 12) { + meridian = " pm" + } + else if (h > 12) { + h -= 12 + meridian = " pm" + } + else { + meridian = " am" + } + + if (d < 10) d = "0" + d + if (m < 10) m = "0" + m + if (pad_hours && h < 10) h = "0" + h + + const date = d + '-' + shortMonths[dateObj.getMonth()] + '-' + dateObj.getFullYear() + const time = h + ':' + m + meridian + + return { date, time } +} +function carbonDate (date, no_bold) { + const span = (+new Date() - new Date(date)) / 1000 + if (! no_bold && span < 86400) // modified today + { color = "new" } + else if (span < 604800) // modifed this week + { color = "recent" } + else if (span < 1209600) // modifed 2 weeks ago + { color = "med" } + else if (span < 3024000) // modifed 5 weeks ago + { color = "old" } + else if (span < 12315200) // modifed 6 months ago + { color = "older" } + else + { color = "quiet" } + return color +} + +function hushViews (n, bias, no_bold) { + const txt = commatize(n) + bias = bias || 1 + n = n || 0 + if (n < 30) { return["quiet", n + " v."] } + if (n < 200) { return ["quiet", txt + " v."] } + else if (n < 500) { return ["quiet", txt + " v."] } + else if (n < 1000) { return ["old", txt + " v."] } + else if (n < 5000) { return ["med", txt + " kv."] } + else if (nobold || n < 10000) { return ["recent", txt + " kv."] } + else { return ["new", txt + " kv."] } +} + +function hushSize (n, bias, nobold) { + const txt = commatize(Math.floor(n / 1024)) + bias = 1 || bias + n = n || 0 + if (n < 1024) { + return ["quiet", n + " b."] + } + if (n < 1024*1024) { + return ["quiet", txt + " kb."] + } + else if (n < (20000000/bias)) { + return ["quiet", txt + " mb."] + } + else if (n < (50000000/bias)) { + return ["old", txt + " mb."] + } + else if (n < (80000000/bias)) { + return ["med", txt + " mb."] + } + else if (nobold || n < (170000000/bias)) { + return ["recent", txt + " mb."] + } + else { + return ["new", txt + " mb."] + } +} + +function hushNull (n, unit, no_bold) { + const s = unit ? n + " " + unit + "." : n + if (n < 3) { + return ["quiet", s] + } + else if (n < 6) { + return ["older", s] + } + else if (n < 10) { + return ["old", s] + } + else if (n < 16) { + return ["med", s] + } + else if (no_bold || n < 21) { + return ["recent", s] + } + else { + return ["new", s] + } +} + +function courtesyS (n, s) { return v == 1 ? "" : (s || "s") } + +const revisionLetters = "z a b c d f g h j k l m n p q r s t v w x y".split(" ") +function getRevision (thread) { + if (! thread.revision) return "" + let rev = thread.revision + let n = 0 + let digits = "" + do { + n = rev % 21 + rev = Math.floor(rev / 21) + digits = revisionLetters[n] + digits + } + while (rev !== 0) + return digits +} + +function getAge (t) { + let age = Math.abs( Date.now()/1000 - t) + const r = Math.floor + let m + if (age < 5) { return "now" } + if (age < 60) { return r(age) + "s" } + age /= 60 + if (age < 60) { return r(age) + "m" } + m = r(age % 60) + age /= 60 + if (m > 0 && age < 2) { return m + "m" + r(age) + "h" } + if (age < 24) { return r(age) + "h" } + age /= 24 + if (age < 7) { return r(age) + "d" } + age /= 7 + if (age < 12) { return r(age) + "w" } + age /= 4 + if (age < 12) { return r(age) + "m" } + age /= 12 + return r(age) + "y" +} + +function tidyURLs (s, short_urls) { + return s.split("\n").map(function(line){ + if (line.indexOf("<") !== -1) { + return line + } + return line.replace(/https?:\/\/[^ ]+/g, function(url){ + if (is_image(url)) { + return '' + } + else if (short_urls) { + return '[' + get_domain(url) + ']' + } + else { + return '' + url + '' + } + }) + }).join("
\n") +} +function getDomain(url){ + return url.replace(/https?:\/\//,"").replace(/\/.*/,"").replace(/www\./, "") +} diff --git a/client/vendor/paths.js b/client/vendor/paths.js new file mode 100644 index 0000000..14c35b1 --- /dev/null +++ b/client/vendor/paths.js @@ -0,0 +1,18 @@ +function filepath (file) { + return '/data/' + file.folder_id + '/' + encodeURIComponent(file.name) +} +function mp3path (file) { + if (file.mime !== 'audio/mp3') { + return filepath(file) + '.mp3' + } + return filepath(file) +} +function pngpath (file) { + return filepath(file) + '.png' +} + +export { + filepath, + mp3path, + pngpath, +} \ No newline at end of file -- cgit v1.2.3-70-g09d2