From 99e7c8a14c1d98166f412be701d954138838c7d6 Mon Sep 17 00:00:00 2001 From: Zaid Abdulla Date: Sun, 24 Jun 2018 13:20:35 -0700 Subject: [PATCH] Implement download tasks --- client/components/device-actions.js | 16 ++++ client/drawer-component.js | 139 ++++++++++++++++++++++------ client/task-queue.js | 5 + config.json | 2 + 4 files changed, 134 insertions(+), 28 deletions(-) diff --git a/client/components/device-actions.js b/client/components/device-actions.js index ccfd728..523c123 100644 --- a/client/components/device-actions.js +++ b/client/components/device-actions.js @@ -43,6 +43,22 @@ const component = { ) ); + buttons.push( + m( + "button.critical", + { + title: "Push a firmware or a config file", + onclick: () => { + taskQueue.stageDownload({ + name: "download", + device: device["DeviceID.ID"].value[0] + }); + } + }, + "Push file" + ) + ); + buttons.push( m( "button.primary", diff --git a/client/drawer-component.js b/client/drawer-component.js index f40a0ac..1631d74 100644 --- a/client/drawer-component.js +++ b/client/drawer-component.js @@ -5,6 +5,7 @@ import m from "mithril"; import * as taskQueue from "./task-queue"; import * as store from "./store"; import * as notifications from "./notifications"; +import Filter from "../common/filter"; function mparam(param) { return m("span.parameter", { title: param }, `${param}`); @@ -14,6 +15,101 @@ function mval(val) { return m("span.value", { title: val }, `${val}`); } +function renderStagingSpv(task, queueFunc, cancelFunc) { + const input = m("input", { + value: task.parameterValues[0][1], + oninput: e => { + e.redraw = false; + task.parameterValues[0][1] = input.dom.value; + }, + onkeydown: e => { + if (e.keyCode === 13) queueFunc(); + else if (e.keyCode === 27) cancelFunc(); + else e.redraw = false; + }, + oncreate: vnode => { + vnode.dom.focus(); + vnode.dom.select(); + // Need to prevent scrolling on focus because + // we're animating height and using overflow: hidden + vnode.dom.parentNode.parentNode.scrollTop = 0; + } + }); + + return [m("span", "Editing ", mparam(task.parameterValues[0][0])), input]; +} + +function renderStagingDownload(task) { + task.invalid = !task.fileName || !task.fileType; + const files = store.fetch("files", new Filter()); + const idParts = task.device.split("-"); + const oui = decodeURIComponent(idParts[0]); + const productClass = + idParts.length === 3 ? decodeURIComponent(idParts[1]) : ""; + + const typesList = [ + "", + "1 Firmware Upgrade Image", + "2 Web Content", + "3 Vendor Configuration File", + "4 Tone File", + "5 Ringer File" + ].map(t => + m( + "option", + { + disabled: !t, + value: t, + selected: (task.fileType || "") === t, + onclick: () => { + task.fileType = t; + } + }, + t + ) + ); + + const filesList = [""] + .concat( + files.value + .filter( + f => + (!f.metadata.oui || f.metadata.oui === oui) && + (!f.metadata.productClass || + f.metadata.productClass === productClass) + ) + .map(f => f._id) + ) + .map(f => + m( + "option", + { + disabled: !f, + value: f, + selected: (task.fileName || "") === f, + onclick: () => { + task.fileName = f; + task.fileType = ""; + for (let file of files.value) + if (file._id === f) task.fileType = file.metadata.fileType; + } + }, + f + ) + ); + + return [ + "Push ", + m( + "select", + { disabled: files.fulfilling, style: "width: 350px" }, + filesList + ), + " as ", + m("select", typesList) + ]; +} + function renderStaging(staging) { let elements = []; for (let s of staging) { @@ -25,29 +121,15 @@ function renderStaging(staging) { staging.delete(s); }; - const input = m("input", { - value: s.parameterValues[0][1], - oninput: e => { - e.redraw = false; - s.parameterValues[0][1] = input.dom.value; - }, - onkeydown: e => { - if (e.keyCode === 13) queueFunc(); - else if (e.keyCode === 27) cancelFunc(); - else e.redraw = false; - }, - oncreate: vnode => { - vnode.dom.focus(); - vnode.dom.select(); - // Need to prevent scrolling on focus because - // we're animating height and using overflow: hidden - vnode.dom.parentNode.parentNode.scrollTop = 0; - } - }); + let elms; + if (s.name === "setParameterValues") + elms = renderStagingSpv(s, queueFunc, cancelFunc); + else if (s.name === "download") + elms = renderStagingDownload(s, queueFunc, cancelFunc); const queue = m( "button.primary", - { title: "Queue task", onclick: queueFunc }, + { title: "Queue task", onclick: queueFunc, disabled: s.invalid }, "Queue" ); const cancel = m( @@ -56,14 +138,7 @@ function renderStaging(staging) { "Cancel" ); - elements.push( - m( - ".staging", - m("span", "Editing ", mparam(s.parameterValues[0][0])), - input, - m("div.actions", queue, cancel) - ) - ); + elements.push(m(".staging", elms, m("div.actions", queue, cancel))); } return elements; } @@ -161,6 +236,14 @@ function renderQueue(queue) { m(".actions", actions) ) ); + else if (t.name === "download") + details.push( + m( + `div.${t.status}`, + `Push file: ${t.fileName} (${t.fileType})`, + m(".actions", actions) + ) + ); else details.push(m(`div.${t.status}`, t.name, m(".actions", actions))); } } diff --git a/client/task-queue.js b/client/task-queue.js index e221e7e..df0b9db 100644 --- a/client/task-queue.js +++ b/client/task-queue.js @@ -36,6 +36,10 @@ function stageSpv(task) { staging.add(task); } +function stageDownload(task) { + staging.add(task); +} + function commit(tasks, callback) { let devices = {}; for (let t of tasks) { @@ -76,5 +80,6 @@ export { getStaging, clearStaging, stageSpv, + stageDownload, commit }; diff --git a/config.json b/config.json index 31bfa93..6016c8c 100644 --- a/config.json +++ b/config.json @@ -11,8 +11,10 @@ "permissions.admin.1.devices.validate.pass": true, "permissions.admin.1.faults.access": 3, "permissions.admin.1.faults.validate.pass": true, + "permissions.admin.1.files.access": 3, "permissions.view.1.devices.access": 2, "permissions.view.1.faults.access": 2, + "permissions.view.1.files.access": 2, "ui.pageSize": 10, "ui.filters.1.label": "Serial number", "ui.filters.1.parameter": "DeviceID.SerialNumber",