[3/3] www: Add reworked web page with bootstrap, dropzone and websocket support

Message ID 1515408521-31480-3-git-send-email-stefan@herbrechtsmeier.net
State New
Headers show
Series
  • [1/3] progress_ipc: Add non-blocking receive support
Related show

Commit Message

Stefan Herbrechtsmeier Jan. 8, 2018, 10:48 a.m.
From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>

The new web page uses WebSocket for the asynchronous communication with the
backend, allows a visualization of different image sources and automatically
reloads the web page after a connection lost.

Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
---
 www2/.gitignore   |   2 +
 www2/LICENSE      |  17 +++++++
 www2/README.md    |  31 +++++++++++++
 www2/gulpfile.js  |  99 ++++++++++++++++++++++++++++++++++++++++
 www2/index.html   | 133 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 www2/logo.png     | Bin 0 -> 24403 bytes
 www2/package.json |  38 ++++++++++++++++
 www2/recovery.css |  36 +++++++++++++++
 www2/recovery.js  | 110 ++++++++++++++++++++++++++++++++++++++++++++
 9 files changed, 466 insertions(+)
 create mode 100644 www2/.gitignore
 create mode 100644 www2/LICENSE
 create mode 100644 www2/README.md
 create mode 100755 www2/gulpfile.js
 create mode 100755 www2/index.html
 create mode 100644 www2/logo.png
 create mode 100755 www2/package.json
 create mode 100755 www2/recovery.css
 create mode 100755 www2/recovery.js

Comments

Stefano Babic Jan. 11, 2018, 8:49 a.m. | #1
Hi Stefan,

On 08/01/2018 11:48, stefan@herbrechtsmeier.net wrote:
> From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
> 
> The new web page uses WebSocket for the asynchronous communication with the
> backend, allows a visualization of different image sources and automatically
> reloads the web page after a connection lost.
> 

First at all, many thanks to provide a very responsive website, that
looks very professional and add features that are currently missing in
the simple website we currently have. It was at the beginning just an
example for website, it was never changed).

I agree to store this in a separate directory, and users can choose
which website they want to have on target. I have some questions for my
understanding:

using npm is straightforward, but I get errors because I had a old
version of nodejs. nodejs is not required on target, but for development
we should write somewhere which are the minimal requirements.

My next issue is with deployment. "npm install" creates a big bunch of
packages that are not needed. As far as I can see in code (and from my
tests), it should be enough for the website to include :

node_modules/bootstrap
node_modules/dropzone
node_modules/jquery

Is there an easy way to deploy the website ? After this will be merged
here, recipes should be added for Yocto.

> Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
> ---
>  www2/.gitignore   |   2 +
>  www2/LICENSE      |  17 +++++++
>  www2/README.md    |  31 +++++++++++++
>  www2/gulpfile.js  |  99 ++++++++++++++++++++++++++++++++++++++++
>  www2/index.html   | 133 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  www2/logo.png     | Bin 0 -> 24403 bytes
>  www2/package.json |  38 ++++++++++++++++
>  www2/recovery.css |  36 +++++++++++++++
>  www2/recovery.js  | 110 ++++++++++++++++++++++++++++++++++++++++++++
>  9 files changed, 466 insertions(+)
>  create mode 100644 www2/.gitignore
>  create mode 100644 www2/LICENSE
>  create mode 100644 www2/README.md
>  create mode 100755 www2/gulpfile.js
>  create mode 100755 www2/index.html
>  create mode 100644 www2/logo.png
>  create mode 100755 www2/package.json
>  create mode 100755 www2/recovery.css
>  create mode 100755 www2/recovery.js
> 
> diff --git a/www2/.gitignore b/www2/.gitignore
> new file mode 100644
> index 0000000..1eae0cf
> --- /dev/null
> +++ b/www2/.gitignore
> @@ -0,0 +1,2 @@
> +dist/
> +node_modules/
> diff --git a/www2/LICENSE b/www2/LICENSE
> new file mode 100644
> index 0000000..fb950dc
> --- /dev/null
> +++ b/www2/LICENSE
> @@ -0,0 +1,17 @@
> +Permission is hereby granted, free of charge, to any person obtaining a copy 
> +of this software and associated documentation files (the "Software"), to deal 
> +in the Software without restriction, including without limitation the rights 
> +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
> +copies of the Software, and to permit persons to whom the Software is 
> +furnished to do so, subject to the following conditions:
> +
> +The above copyright notice and this permission notice shall be included in 
> +all copies or substantial portions of the Software.
> +
> +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
> +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
> +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
> +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
> +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
> +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 
> +THE SOFTWARE.
For a FOSS project, it should be easy to identify for each file which is
its license. I am not sure if this way is correct (anyway, it is the
same way for dropzone and bootstap). Just to mention if somebody argues.

> diff --git a/www2/README.md b/www2/README.md
> new file mode 100644
> index 0000000..abb6199
> --- /dev/null
> +++ b/www2/README.md
> @@ -0,0 +1,31 @@
> +SWUpdate Web Page
> +=================
> +
> +The SWUpdate web page uses the NPM package manager and depends on
> +Bootstrap and DropzoneJS.
> +
> +It uses WebSocket for the asynchronous communication with the backend,
> +allows a visualization of different image sources and automatically
> +reloads the web page after a connection lost.
> +
> +
> +Install
> +-------
> +
> +```sh
> +npm install
> +```
> +
> +Build
> +-----
> +
> +```sh
> +npm run build
> +```
> +
> +Lint
> +----
> +
> +```sh
> +npm run lint
> +```

I guess that this should be part of the documentation under doc/, better
with a complete new chapter (web development or website).

> diff --git a/www2/gulpfile.js b/www2/gulpfile.js

As I said, we need some way to split between development and deployment.
This file is for development, not for deployment.
It could also be an additional target in Makefile, if things are easier.

> new file mode 100755
> index 0000000..e740451
> --- /dev/null
> +++ b/www2/gulpfile.js
> @@ -0,0 +1,99 @@
> +var cleanCSS = require('gulp-clean-css')
> +var del = require('del')
> +var gulp = require('gulp')
> +var favicons = require('gulp-favicons')
> +var htmlmin = require('gulp-htmlmin')
> +var htmlreplace = require('gulp-html-replace')
> +var minify = require('gulp-minify')
> +var rename = require('gulp-rename')
> +var responsive = require('gulp-responsive')
> +
> +gulp.task('minify-css', ['clean'], () => {
> +  return gulp.src('recovery.css')
> +    .pipe(cleanCSS({ compatibility: 'ie8' }))
> +    .pipe(rename({
> +      suffix: '.min'
> +    }))
> +    .pipe(gulp.dest('dist/css'))
> +})
> +
> +gulp.task('minify-js', ['clean'], () => {
> +  return gulp.src('recovery.js')
> +    .pipe(minify({
> +      ext: {
> +        min: '.min.js'
> +      },
> +      noSource: true
> +    }))
> +    .pipe(gulp.dest('dist/js'))
> +})
> +
> +gulp.task('minify-html', ['clean'], () => {
> +  return gulp.src('index.html')
> +    .pipe(htmlreplace({
> +      'js': ['js/jquery.min.js', 'js/bootstrap.min.js', 'js/dropzone.min.js', 'js/recovery.min.js'],
> +      'css': ['css/bootstrap.min.css', 'css/dropzone.min.css', 'css/recovery.min.css']
> +    }))
> +    .pipe(htmlmin({ collapseWhitespace: true }))
> +    .pipe(gulp.dest('dist'))
> +})
> +
> +gulp.task('copy-css', ['clean'], () => {
> +  return gulp.src([
> +    'node_modules/bootstrap/dist/css/bootstrap.min.css',
> +    'node_modules/dropzone/dist/min/dropzone.min.css'
> +  ])
> +      .pipe(gulp.dest('dist/css'))
> +})
> +
> +gulp.task('copy-js', ['clean'], () => {
> +  return gulp.src([
> +    'node_modules/jquery/dist/jquery.min.js',
> +    'node_modules/bootstrap/dist/js/bootstrap.min.js',
> +    'node_modules/dropzone/dist/min/dropzone.min.js'
> +  ])
> +      .pipe(gulp.dest('dist/js'))
> +})
> +
> +gulp.task('copy-fonts', ['clean'], () => {
> +  return gulp.src([
> +    'node_modules/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf',
> +    'node_modules/bootstrap/dist/fonts/glyphicons-halflings-regular.woff',
> +    'node_modules/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2'
> +  ])
> +      .pipe(gulp.dest('dist/fonts'))
> +})
> +
> +gulp.task('resize-images', function () {
> +  return gulp.src('logo.png')
> +    .pipe(responsive({
> +      'logo.png': {
> +        height: 200
> +      }
> +    }))
> +    .pipe(gulp.dest('dist'))
> +})
> +
> +gulp.task('favicons', ['clean'], () => {
> +  return gulp.src('logo.png').pipe(favicons({
> +    icons: {
> +      android: false,
> +      appleIcon: false,
> +      appleStartup: false,
> +      coast: false,
> +      favicons: true,
> +      firefox: false,
> +      windows: false,
> +      yandex: false
> +    }
> +  }))
> +    .pipe(gulp.dest('dist'))
> +})
> +
> +gulp.task('clean', () => {
> +  return del('dist/**', { force: true })
> +})
> +
> +gulp.task('build', ['copy-css', 'copy-js', 'copy-fonts', 'resize-images', 'minify-js', 'minify-css', 'minify-html', 'favicons'])
> +
> +gulp.task('default', ['build'])
> diff --git a/www2/index.html b/www2/index.html
> new file mode 100755
> index 0000000..1177081
> --- /dev/null
> +++ b/www2/index.html
> @@ -0,0 +1,133 @@
> +<!DOCTYPE html>
> +<html lang="en">
> +
> +<head>
> +  <meta charset="UTF-8">
> +  <title>Firmware Update</title>
> +
> +  <!-- build:css -->
> +  <link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.min.css">
> +  <link rel="stylesheet" href="node_modules/dropzone/dist/min/dropzone.min.css">        
> +  <link rel="stylesheet" href="recovery.css">
> +  <!-- endbuild -->
> +
> +  <!-- build:js -->
> +  <script src="node_modules/jquery/dist/jquery.min.js"></script>
> +  <script src="node_modules/bootstrap/dist/js/bootstrap.min.js"></script>
> +  <script src="node_modules/dropzone/dist/min/dropzone.min.js"></script>
> +  <script src="recovery.js"></script>
> +  <!-- endbuild -->
> +</head>
> +
> +<body>
> +  <!-- Use Bootstrap Grid Container -->
> +  <div class="container">
> +
> +    <div class="page-header">
> +      <h1><img src="logo.png" height="50">SWUpdate</h1>
> +    </div>
> +
> +    <div class="row">
> +      <div class="col-lg-12 col-md-12 col-xs-12">
> +        <legend>
> +          <h2>
> +            Firmware Update
> +            <div class="pull-right">
> +              <label class="custom-control custom-checkbox label">
> +                <input id="swu-auto-restart" class="form-check-input" type="checkbox" value=""><small> Restart system after update finished</small>
> +              </label>
> +              <button type="button" class="btn btn-primary" onclick="restart()">
> +                <span class="glyphicon glyphicon-refresh"></span> Restart system 
> +              </button>
> +            </div>
> +          </h2>
> +        </legend>
> +      </div>
> +    </div>
> +
> +    <!-- Dropzone Button for drag&drop files -->
> +    <div class="row">
> +      <div class="col-lg-12 col-md-12 col-xs-12">
> +        <form class="dropzone panel" id="dropzone" action="/upload" method="post" enctype="multipart/form-data">
> +          <div class="dz-default dz-message">
> +            <span class="dz-message">Drop file here or click to upload a firmware update image.</span>
> +          </div>
> +        </form>
> +        <br>
> +      </div>
> +    </div>
> +
> +    <!-- Warning -->
> +    <div class="row">
> +      <div class="col-lg-12 col-md-12 col-xs-12">
> +        <div id="swu-warning" class="alert alert-warning" hidden="hidden">
> +          <span class="glyphicon glyphicon glyphicon-warning-sign"></span> Update firmware may take a few minutes, please don't turn off the power.
> +        </div>
> +      </div>
> +    </div>
> +
> +    <!-- Progress Bar -->
> +    <div class="row">
> +      <div id="swu-progress" class="col-lg-12 col-md-12 col-xs-12" hidden="hidden">
> +        <div>
> +          <strong>Installing:</strong>
> +          <span id="swu-progress-name"></span>
> +          <span id="swu-progress-value" class="pull-right"></span>
> +        </div>
> +        <div class="progress">
> +          <div id="swu-progress-bar" class="progress-bar" role="progressbar"></div>
> +        </div>
> +      </div>
> +     </div>
> +
> +    <!-- Status -->
> +    <div class="row">
> +      <div class="col-lg-12 col-md-12 col-xs-12">
> +        <div id="swu-success" class="alert alert-success" hidden="hidden">
> +          <span class="glyphicon glyphicon-ok"></span> Successful updated
> +        </div>
> +        <div id="swu-failure" class="alert alert-danger" hidden="hidden">
> +          <span class="glyphicon glyphicon glyphicon-remove"></span> Update failed
> +        </div>
> +      </div>
> +    </div>
> +
> +    <!-- Messages -->
> +    <div class="row">
> +      <div class="col-lg-12 col-md-12 col-xs-12">
> +        <div class="panel-group">
> +          <div class="panel panel-default">
> +            <div class="panel-heading">
> +              <h4 class="panel-title">
> +                <a class="collapsed" data-toggle="collapse" href="#collapse" aria-expanded="false">Details</a>
> +              </h4>
> +            </div>
> +            <div id="collapse" class="panel-collapse collapse">
> +              <div class="panel-body" id="messages"></div>
> +            </div>
> +          </div>
> +        </div>
> +      </div>
> +    </div>
> +
> +    <!-- Restart -->
> +    <div id="swu-restart" class="modal fade" tabindex="-1" role="dialog">
> +      <div class="modal-dialog modal-sm" role="document">
> +        <div class="modal-content">
> +          <div class="modal-body">
> +            <div class="row">
> +              <div class="col-md-4">
> +                <div  class="loader"></div>
> +              </div>
> +              <div class="col-md-8">
> +              <p>The system will restart. Please be patient, as restarting takes about one minute.</p>
> +            </div>
> +            </div>
> +          </div>
> +        </div>
> +      </div>
> +    </div>
> +  </div>
> +</body>
> +
> +</html>
> \ No newline at end of file
> diff --git a/www2/logo.png b/www2/logo.png

It is real a pity that the file is copied because it is already stored
in repo. I would like to avoid this.

> new file mode 100644
> index 0000000000000000000000000000000000000000..12ee4c41284a56a092499d4452641f6ef67fec83
> GIT binary patch
> literal 24403
> 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
> 
> literal 0
> HcmV?d00001
> 
> diff --git a/www2/package.json b/www2/package.json
> new file mode 100755
> index 0000000..4dc22e1
> --- /dev/null
> +++ b/www2/package.json
> @@ -0,0 +1,38 @@
> +{
> +  "name": "swupdate",
> +  "version": "0.1.0",
> +  "description": "",
> +  "main": "index.html",
> +  "scripts": {
> +    "htmlhint": "htmlhint *.html",
> +    "standard": "standard --fix *.js",
> +    "lint": "standard && htmlhint",
> +    "build": "gulp",
> +    "clean": "gulp clean"
> +  },
> +  "author": "",
> +  "license": "MIT",
> +  "devDependencies": {
> +    "del": "^3.0.0",
> +    "gulp": "^3.9.1",
> +    "gulp-clean-css": "^3.9.0",
> +    "gulp-favicons": "^2.2.7",
> +    "gulp-html-replace": "^1.6.2",
> +    "gulp-htmlmin": "^3.0.0",
> +    "gulp-minify": "^2.1.0",
> +    "gulp-rename": "^1.2.2",
> +    "gulp-responsive": "^2.8.0",
> +    "htmlhint": "^0.9.13",
> +    "standard": "^10.0.3"
> +  },
> +  "dependencies": {
> +    "bootstrap": "^3.3.7",
> +    "dropzone": "5.2.0",
> +    "jquery": "^3.2.1"
> +  },
> +  "standard": {
> +    "ignore": [
> +      "dist"
> +    ]
> +  }
> +}
> diff --git a/www2/recovery.css b/www2/recovery.css
> new file mode 100755
> index 0000000..3fe3492
> --- /dev/null
> +++ b/www2/recovery.css
> @@ -0,0 +1,36 @@
> +h1 img {
> +  margin-left: 10px;
> +  margin-right: 10px;
> +}
> +
> +.dropzone .dz-preview .dz-image {
> +  width: 240px;
> +}
> +
> +.loader {
> +  border: 10px solid LightGray; /* Light grey */
> +  border-top: 10px solid Black; /* Blue */
> +  border-bottom: 10px solid Black; /* Blue */
> +  border-radius: 50%;
> +  width: 80px;
> +  height: 80px;
> +  animation: spin 2s linear infinite;
> +}
> +
> +@keyframes spin {
> +  0% { transform: rotate(0deg); }
> +  100% { transform: rotate(360deg); }
> +}
> +
> +.panel-group .panel-title>a:before {
> +  font-family: 'Glyphicons Halflings';
> +  content: "\e114";
> +  display: inline-block;
> +  font-size: 13px;
> +  margin-right: 8px;
> +  text-align: center;
> +}
> +
> +.panel-group .panel-title>a.collapsed:before {
> +  content: "\e080";
> +}
> diff --git a/www2/recovery.js b/www2/recovery.js
> new file mode 100755
> index 0000000..9836831
> --- /dev/null
> +++ b/www2/recovery.js
> @@ -0,0 +1,110 @@
> +/*
> + * Copyright (C) 2017 Weidmüller Interface GmbH & Co. KG
> + * Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
> + *
> + * SPDX-License-Identifier: MIT
> + */
> +
> +/* global $, Dropzone, WebSocket */
> +
> +function restart () {
> +  $.post('restart', {}, function (data) {
> +    showRestart()
> +  })
> +};
> +
> +function showRestart () {
> +  $('#swu-restart').modal({backdrop: 'static', keyboard: false})
> +  window.setTimeout(tryReload, 3000)
> +}
> +function tryReload () {
> +  $.ajax({
> +    cache: false,
> +    timeout: 1000,
> +    success: function (response) {
> +      window.location.reload(true)
> +    },
> +    error: function (xhr, textStatus, errorThrown) {
> +      if (textStatus === 'timeout') { tryReload() }
> +      window.setTimeout(tryReload, 1000)
> +    }
> +  })
> +}
> +
> +Dropzone.options.dropzone = {
> +  clickable: true,
> +  acceptedFiles: '.swu'
> +}
> +
> +window.onload = function () {
> +  var protocol
> +
> +  if (window.location.protocol === 'https:') { protocol = 'wss:' } else { protocol = 'ws:' }
> +
> +  var ws = new WebSocket(protocol + '//' + window.location.host + '/ws')
> +
> +  ws.onclose = function (event) {
> +    showRestart()
> +  }
> +
> +  ws.onmessage = function (event) {
> +    var msg = JSON.parse(event.data)
> +
> +    switch (msg.type) {
> +      case 'message':
> +        if (msg.level <= 3) {
> +          $('#messages').append('<p class="text-danger">' + msg.text + '</p>')
> +        } else {
> +          $('#messages').append('<p>' + msg.text + '</p>')
> +        }
> +        break
> +      case 'status':
> +        switch (msg.status) {
> +          case 'START':
> +            $('#swu-progress').hide()
> +            $('#swu-success').hide()
> +            $('#swu-failure').hide()
> +            $('#swu-warning').show()
> +            break
> +          case 'RUN':
> +            break
> +          case 'SUCCESS':
> +            $('#swu-progress').hide()
> +            $('#swu-warning').hide()
> +            $('#swu-failure').hide()
> +            $('#swu-success').show()
> +            if ($('#swu-auto-restart').prop('checked')) { restart() }
> +            break
> +          case 'FAILURE':
> +            $('#swu-progress').hide()
> +            $('#swu-warning').hide()
> +            $('#swu-success').hide()
> +            $('#swu-failure').show()
> +            break
> +          case 'DONE':
> +            $('#swu-progress').hide()
> +            $('#swu-warning').hide()
> +            $('#swu-success').hide()
> +            $('#swu-failure').hide()
> +            break
> +          default:
> +            console.log(msg)
> +            break
> +        }
> +        break
> +      case 'source':
> +        break
> +      case 'step':
> +        var percent = Math.round((100 * (Number(msg.step) - 1) + Number(msg.percent)) / Number(msg.number))
> +
> +        $('#swu-progress-value').html(percent + '%' + ' (' + msg.step + ' of ' + msg.number + ')')
> +        $('#swu-progress-name').html(msg.name)
> +        $('#swu-progress-bar')
> +        .css('width', percent + '%')
> +        .attr('aria-valuenow', percent)
> +
> +        $('#swu-progress').show()
> +        break
> +    }
> +  }
> +}
> 

Anyway, from my first tests the website is quite impressive - a big
improvement from current state !

Best regards,
Stefano
Stefan Herbrechtsmeier Jan. 11, 2018, 9:02 a.m. | #2
Hi Stefano,

> -----Ursprüngliche Nachricht-----
> Von: Stefano Babic [mailto:sbabic@denx.de]
> Gesendet: Donnerstag, 11. Januar 2018 09:50
> An: stefan@herbrechtsmeier.net; swupdate@googlegroups.com
> Cc: Herbrechtsmeier Dr.-Ing. , Stefan
> <Stefan.Herbrechtsmeier@weidmueller.com>
> Betreff: Re: [swupdate] [PATCH 3/3] www: Add reworked web page with
> bootstrap, dropzone and websocket support
>
> On 08/01/2018 11:48, stefan@herbrechtsmeier.net wrote:
> > From: Stefan Herbrechtsmeier
> <stefan.herbrechtsmeier@weidmueller.com>
> >
> > The new web page uses WebSocket for the asynchronous communication
> with the
> > backend, allows a visualization of different image sources and automatically
> > reloads the web page after a connection lost.
> >
>
> First at all, many thanks to provide a very responsive website, that
> looks very professional and add features that are currently missing in
> the simple website we currently have. It was at the beginning just an
> example for website, it was never changed).
>
> I agree to store this in a separate directory, and users can choose
> which website they want to have on target. I have some questions for my
> understanding:

Maybe we should even use a separate project repository.

> using npm is straightforward, but I get errors because I had a old
> version of nodejs. nodejs is not required on target, but for development
> we should write somewhere which are the minimal requirements.

Okay

> My next issue is with deployment. "npm install" creates a big bunch of
> packages that are not needed. As far as I can see in code (and from my
> tests), it should be enough for the website to include :
>
> node_modules/bootstrap
> node_modules/dropzone
> node_modules/jquery
>
> Is there an easy way to deploy the website ? After this will be merged
> here, recipes should be added for Yocto.

You can generate the website with the "npm run build" this will generate a deploy version in the dict folder.

> > Signed-off-by: Stefan Herbrechtsmeier
> <stefan.herbrechtsmeier@weidmueller.com>
> > ---
> >  www2/.gitignore   |   2 +
> >  www2/LICENSE      |  17 +++++++
> >  www2/README.md    |  31 +++++++++++++
> >  www2/gulpfile.js  |  99
> ++++++++++++++++++++++++++++++++++++++++
> >  www2/index.html   | 133
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++
> >  www2/logo.png     | Bin 0 -> 24403 bytes
> >  www2/package.json |  38 ++++++++++++++++
> >  www2/recovery.css |  36 +++++++++++++++
> >  www2/recovery.js  | 110
> ++++++++++++++++++++++++++++++++++++++++++++
> >  9 files changed, 466 insertions(+)
> >  create mode 100644 www2/.gitignore
> >  create mode 100644 www2/LICENSE
> >  create mode 100644 www2/README.md
> >  create mode 100755 www2/gulpfile.js
> >  create mode 100755 www2/index.html
> >  create mode 100644 www2/logo.png
> >  create mode 100755 www2/package.json
> >  create mode 100755 www2/recovery.css
> >  create mode 100755 www2/recovery.js
> >
> > diff --git a/www2/.gitignore b/www2/.gitignore
> > new file mode 100644
> > index 0000000..1eae0cf
> > --- /dev/null
> > +++ b/www2/.gitignore
> > @@ -0,0 +1,2 @@
> > +dist/
> > +node_modules/
> > diff --git a/www2/LICENSE b/www2/LICENSE
> > new file mode 100644
> > index 0000000..fb950dc
> > --- /dev/null
> > +++ b/www2/LICENSE
> > @@ -0,0 +1,17 @@
> > +Permission is hereby granted, free of charge, to any person obtaining a
> copy
> > +of this software and associated documentation files (the "Software"), to
> deal
> > +in the Software without restriction, including without limitation the rights
> > +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> > +copies of the Software, and to permit persons to whom the Software is
> > +furnished to do so, subject to the following conditions:
> > +
> > +The above copyright notice and this permission notice shall be included in
> > +all copies or substantial portions of the Software.
> > +
> > +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> EXPRESS OR
> > +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> MERCHANTABILITY,
> > +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
> EVENT SHALL THE
> > +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
> OR OTHER
> > +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> ARISING FROM,
> > +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
> DEALINGS IN
> > +THE SOFTWARE.
> For a FOSS project, it should be easy to identify for each file which is
> its license. I am not sure if this way is correct (anyway, it is the
> same way for dropzone and bootstap). Just to mention if somebody argues.

Okay

> > diff --git a/www2/README.md b/www2/README.md
> > new file mode 100644
> > index 0000000..abb6199
> > --- /dev/null
> > +++ b/www2/README.md
> > @@ -0,0 +1,31 @@
> > +SWUpdate Web Page
> > +=================
> > +
> > +The SWUpdate web page uses the NPM package manager and depends
> on
> > +Bootstrap and DropzoneJS.
> > +
> > +It uses WebSocket for the asynchronous communication with the
> backend,
> > +allows a visualization of different image sources and automatically
> > +reloads the web page after a connection lost.
> > +
> > +
> > +Install
> > +-------
> > +
> > +```sh
> > +npm install
> > +```
> > +
> > +Build
> > +-----
> > +
> > +```sh
> > +npm run build
> > +```
> > +
> > +Lint
> > +----
> > +
> > +```sh
> > +npm run lint
> > +```
>
> I guess that this should be part of the documentation under doc/, better
> with a complete new chapter (web development or website).

You are right. This was only a first version to get some feedback.

> > diff --git a/www2/gulpfile.js b/www2/gulpfile.js
>
> As I said, we need some way to split between development and
> deployment.
> This file is for development, not for deployment.
> It could also be an additional target in Makefile, if things are easier.

I would separate the web development. Maybe we could integrate only the deployment into this project or even better download a release from the website project.

<snip>

> Anyway, from my first tests the website is quite impressive - a big
> improvement from current state !

Thank you and best regards

Stefan Herbrechtsmeier
Software Developer Embedded Systems

Weidmüller – Your partner in Industrial Connectivity
We look forward to sharing ideas with you – Let’s connect.

Weidmueller Interface GmbH & Co. KG
Klingenbergstraße 16, 32758 Detmold, Germany
Email: Stefan.Herbrechtsmeier@weidmueller.com – Web: www.weidmueller.com
Stefano Babic Jan. 11, 2018, 9:15 a.m. | #3
Hi Stefan,

On 11/01/2018 10:02, Stefan.Herbrechtsmeier@weidmueller.com wrote:
> Hi Stefano,
> 
>> -----Ursprüngliche Nachricht-----
>> Von: Stefano Babic [mailto:sbabic@denx.de]
>> Gesendet: Donnerstag, 11. Januar 2018 09:50
>> An: stefan@herbrechtsmeier.net; swupdate@googlegroups.com
>> Cc: Herbrechtsmeier Dr.-Ing. , Stefan
>> <Stefan.Herbrechtsmeier@weidmueller.com>
>> Betreff: Re: [swupdate] [PATCH 3/3] www: Add reworked web page with
>> bootstrap, dropzone and websocket support
>>
>> On 08/01/2018 11:48, stefan@herbrechtsmeier.net wrote:
>>> From: Stefan Herbrechtsmeier
>> <stefan.herbrechtsmeier@weidmueller.com>
>>>
>>> The new web page uses WebSocket for the asynchronous communication
>> with the
>>> backend, allows a visualization of different image sources and automatically
>>> reloads the web page after a connection lost.
>>>
>>
>> First at all, many thanks to provide a very responsive website, that
>> looks very professional and add features that are currently missing in
>> the simple website we currently have. It was at the beginning just an
>> example for website, it was never changed).
>>
>> I agree to store this in a separate directory, and users can choose
>> which website they want to have on target. I have some questions for my
>> understanding:
> 
> Maybe we should even use a separate project repository.
> 

This is another option, I am also thinking about of it.

>> using npm is straightforward, but I get errors because I had a old
>> version of nodejs. nodejs is not required on target, but for development
>> we should write somewhere which are the minimal requirements.
> 
> Okay
> 
>> My next issue is with deployment. "npm install" creates a big bunch of
>> packages that are not needed. As far as I can see in code (and from my
>> tests), it should be enough for the website to include :
>>
>> node_modules/bootstrap
>> node_modules/dropzone
>> node_modules/jquery
>>
>> Is there an easy way to deploy the website ? After this will be merged
>> here, recipes should be added for Yocto.
> 
> You can generate the website with the "npm run build" this will generate a deploy version in the dict folder.

Ok, thanks !

> 
>>> Signed-off-by: Stefan Herbrechtsmeier
>> <stefan.herbrechtsmeier@weidmueller.com>
>>> ---
>>>  www2/.gitignore   |   2 +
>>>  www2/LICENSE      |  17 +++++++
>>>  www2/README.md    |  31 +++++++++++++
>>>  www2/gulpfile.js  |  99
>> ++++++++++++++++++++++++++++++++++++++++
>>>  www2/index.html   | 133
>> ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>>  www2/logo.png     | Bin 0 -> 24403 bytes
>>>  www2/package.json |  38 ++++++++++++++++
>>>  www2/recovery.css |  36 +++++++++++++++
>>>  www2/recovery.js  | 110
>> ++++++++++++++++++++++++++++++++++++++++++++
>>>  9 files changed, 466 insertions(+)
>>>  create mode 100644 www2/.gitignore
>>>  create mode 100644 www2/LICENSE
>>>  create mode 100644 www2/README.md
>>>  create mode 100755 www2/gulpfile.js
>>>  create mode 100755 www2/index.html
>>>  create mode 100644 www2/logo.png
>>>  create mode 100755 www2/package.json
>>>  create mode 100755 www2/recovery.css
>>>  create mode 100755 www2/recovery.js
>>>
>>> diff --git a/www2/.gitignore b/www2/.gitignore
>>> new file mode 100644
>>> index 0000000..1eae0cf
>>> --- /dev/null
>>> +++ b/www2/.gitignore
>>> @@ -0,0 +1,2 @@
>>> +dist/
>>> +node_modules/
>>> diff --git a/www2/LICENSE b/www2/LICENSE
>>> new file mode 100644
>>> index 0000000..fb950dc
>>> --- /dev/null
>>> +++ b/www2/LICENSE
>>> @@ -0,0 +1,17 @@
>>> +Permission is hereby granted, free of charge, to any person obtaining a
>> copy
>>> +of this software and associated documentation files (the "Software"), to
>> deal
>>> +in the Software without restriction, including without limitation the rights
>>> +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
>>> +copies of the Software, and to permit persons to whom the Software is
>>> +furnished to do so, subject to the following conditions:
>>> +
>>> +The above copyright notice and this permission notice shall be included in
>>> +all copies or substantial portions of the Software.
>>> +
>>> +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
>> EXPRESS OR
>>> +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
>> MERCHANTABILITY,
>>> +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
>> EVENT SHALL THE
>>> +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
>> OR OTHER
>>> +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
>> ARISING FROM,
>>> +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
>> DEALINGS IN
>>> +THE SOFTWARE.
>> For a FOSS project, it should be easy to identify for each file which is
>> its license. I am not sure if this way is correct (anyway, it is the
>> same way for dropzone and bootstap). Just to mention if somebody argues.
> 
> Okay
> 
>>> diff --git a/www2/README.md b/www2/README.md
>>> new file mode 100644
>>> index 0000000..abb6199
>>> --- /dev/null
>>> +++ b/www2/README.md
>>> @@ -0,0 +1,31 @@
>>> +SWUpdate Web Page
>>> +=================
>>> +
>>> +The SWUpdate web page uses the NPM package manager and depends
>> on
>>> +Bootstrap and DropzoneJS.
>>> +
>>> +It uses WebSocket for the asynchronous communication with the
>> backend,
>>> +allows a visualization of different image sources and automatically
>>> +reloads the web page after a connection lost.
>>> +
>>> +
>>> +Install
>>> +-------
>>> +
>>> +```sh
>>> +npm install
>>> +```
>>> +
>>> +Build
>>> +-----
>>> +
>>> +```sh
>>> +npm run build
>>> +```
>>> +
>>> +Lint
>>> +----
>>> +
>>> +```sh
>>> +npm run lint
>>> +```
>>
>> I guess that this should be part of the documentation under doc/, better
>> with a complete new chapter (web development or website).
> 
> You are right. This was only a first version to get some feedback.
> 
>>> diff --git a/www2/gulpfile.js b/www2/gulpfile.js
>>
>> As I said, we need some way to split between development and
>> deployment.
>> This file is for development, not for deployment.
>> It could also be an additional target in Makefile, if things are easier.
> 
> I would separate the web development. Maybe we could integrate only the deployment into this project or even better download a release from the website project.

Agree, it looks to me the best way. We let development in SWUpdate repo,
and I will create a separate repo for the website project to get
release. This simplifies the integration into Yocto, too.

> 
> <snip>
> 
>> Anyway, from my first tests the website is quite impressive - a big
>> improvement from current state !
> 
> Thank you and best regards

Best regards,
Stefano Babic

Patch

diff --git a/www2/.gitignore b/www2/.gitignore
new file mode 100644
index 0000000..1eae0cf
--- /dev/null
+++ b/www2/.gitignore
@@ -0,0 +1,2 @@ 
+dist/
+node_modules/
diff --git a/www2/LICENSE b/www2/LICENSE
new file mode 100644
index 0000000..fb950dc
--- /dev/null
+++ b/www2/LICENSE
@@ -0,0 +1,17 @@ 
+Permission is hereby granted, free of charge, to any person obtaining a copy 
+of this software and associated documentation files (the "Software"), to deal 
+in the Software without restriction, including without limitation the rights 
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
+copies of the Software, and to permit persons to whom the Software is 
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in 
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 
+THE SOFTWARE.
diff --git a/www2/README.md b/www2/README.md
new file mode 100644
index 0000000..abb6199
--- /dev/null
+++ b/www2/README.md
@@ -0,0 +1,31 @@ 
+SWUpdate Web Page
+=================
+
+The SWUpdate web page uses the NPM package manager and depends on
+Bootstrap and DropzoneJS.
+
+It uses WebSocket for the asynchronous communication with the backend,
+allows a visualization of different image sources and automatically
+reloads the web page after a connection lost.
+
+
+Install
+-------
+
+```sh
+npm install
+```
+
+Build
+-----
+
+```sh
+npm run build
+```
+
+Lint
+----
+
+```sh
+npm run lint
+```
diff --git a/www2/gulpfile.js b/www2/gulpfile.js
new file mode 100755
index 0000000..e740451
--- /dev/null
+++ b/www2/gulpfile.js
@@ -0,0 +1,99 @@ 
+var cleanCSS = require('gulp-clean-css')
+var del = require('del')
+var gulp = require('gulp')
+var favicons = require('gulp-favicons')
+var htmlmin = require('gulp-htmlmin')
+var htmlreplace = require('gulp-html-replace')
+var minify = require('gulp-minify')
+var rename = require('gulp-rename')
+var responsive = require('gulp-responsive')
+
+gulp.task('minify-css', ['clean'], () => {
+  return gulp.src('recovery.css')
+    .pipe(cleanCSS({ compatibility: 'ie8' }))
+    .pipe(rename({
+      suffix: '.min'
+    }))
+    .pipe(gulp.dest('dist/css'))
+})
+
+gulp.task('minify-js', ['clean'], () => {
+  return gulp.src('recovery.js')
+    .pipe(minify({
+      ext: {
+        min: '.min.js'
+      },
+      noSource: true
+    }))
+    .pipe(gulp.dest('dist/js'))
+})
+
+gulp.task('minify-html', ['clean'], () => {
+  return gulp.src('index.html')
+    .pipe(htmlreplace({
+      'js': ['js/jquery.min.js', 'js/bootstrap.min.js', 'js/dropzone.min.js', 'js/recovery.min.js'],
+      'css': ['css/bootstrap.min.css', 'css/dropzone.min.css', 'css/recovery.min.css']
+    }))
+    .pipe(htmlmin({ collapseWhitespace: true }))
+    .pipe(gulp.dest('dist'))
+})
+
+gulp.task('copy-css', ['clean'], () => {
+  return gulp.src([
+    'node_modules/bootstrap/dist/css/bootstrap.min.css',
+    'node_modules/dropzone/dist/min/dropzone.min.css'
+  ])
+      .pipe(gulp.dest('dist/css'))
+})
+
+gulp.task('copy-js', ['clean'], () => {
+  return gulp.src([
+    'node_modules/jquery/dist/jquery.min.js',
+    'node_modules/bootstrap/dist/js/bootstrap.min.js',
+    'node_modules/dropzone/dist/min/dropzone.min.js'
+  ])
+      .pipe(gulp.dest('dist/js'))
+})
+
+gulp.task('copy-fonts', ['clean'], () => {
+  return gulp.src([
+    'node_modules/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf',
+    'node_modules/bootstrap/dist/fonts/glyphicons-halflings-regular.woff',
+    'node_modules/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2'
+  ])
+      .pipe(gulp.dest('dist/fonts'))
+})
+
+gulp.task('resize-images', function () {
+  return gulp.src('logo.png')
+    .pipe(responsive({
+      'logo.png': {
+        height: 200
+      }
+    }))
+    .pipe(gulp.dest('dist'))
+})
+
+gulp.task('favicons', ['clean'], () => {
+  return gulp.src('logo.png').pipe(favicons({
+    icons: {
+      android: false,
+      appleIcon: false,
+      appleStartup: false,
+      coast: false,
+      favicons: true,
+      firefox: false,
+      windows: false,
+      yandex: false
+    }
+  }))
+    .pipe(gulp.dest('dist'))
+})
+
+gulp.task('clean', () => {
+  return del('dist/**', { force: true })
+})
+
+gulp.task('build', ['copy-css', 'copy-js', 'copy-fonts', 'resize-images', 'minify-js', 'minify-css', 'minify-html', 'favicons'])
+
+gulp.task('default', ['build'])
diff --git a/www2/index.html b/www2/index.html
new file mode 100755
index 0000000..1177081
--- /dev/null
+++ b/www2/index.html
@@ -0,0 +1,133 @@ 
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+  <meta charset="UTF-8">
+  <title>Firmware Update</title>
+
+  <!-- build:css -->
+  <link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.min.css">
+  <link rel="stylesheet" href="node_modules/dropzone/dist/min/dropzone.min.css">        
+  <link rel="stylesheet" href="recovery.css">
+  <!-- endbuild -->
+
+  <!-- build:js -->
+  <script src="node_modules/jquery/dist/jquery.min.js"></script>
+  <script src="node_modules/bootstrap/dist/js/bootstrap.min.js"></script>
+  <script src="node_modules/dropzone/dist/min/dropzone.min.js"></script>
+  <script src="recovery.js"></script>
+  <!-- endbuild -->
+</head>
+
+<body>
+  <!-- Use Bootstrap Grid Container -->
+  <div class="container">
+
+    <div class="page-header">
+      <h1><img src="logo.png" height="50">SWUpdate</h1>
+    </div>
+
+    <div class="row">
+      <div class="col-lg-12 col-md-12 col-xs-12">
+        <legend>
+          <h2>
+            Firmware Update
+            <div class="pull-right">
+              <label class="custom-control custom-checkbox label">
+                <input id="swu-auto-restart" class="form-check-input" type="checkbox" value=""><small> Restart system after update finished</small>
+              </label>
+              <button type="button" class="btn btn-primary" onclick="restart()">
+                <span class="glyphicon glyphicon-refresh"></span> Restart system 
+              </button>
+            </div>
+          </h2>
+        </legend>
+      </div>
+    </div>
+
+    <!-- Dropzone Button for drag&drop files -->
+    <div class="row">
+      <div class="col-lg-12 col-md-12 col-xs-12">
+        <form class="dropzone panel" id="dropzone" action="/upload" method="post" enctype="multipart/form-data">
+          <div class="dz-default dz-message">
+            <span class="dz-message">Drop file here or click to upload a firmware update image.</span>
+          </div>
+        </form>
+        <br>
+      </div>
+    </div>
+
+    <!-- Warning -->
+    <div class="row">
+      <div class="col-lg-12 col-md-12 col-xs-12">
+        <div id="swu-warning" class="alert alert-warning" hidden="hidden">
+          <span class="glyphicon glyphicon glyphicon-warning-sign"></span> Update firmware may take a few minutes, please don't turn off the power.
+        </div>
+      </div>
+    </div>
+
+    <!-- Progress Bar -->
+    <div class="row">
+      <div id="swu-progress" class="col-lg-12 col-md-12 col-xs-12" hidden="hidden">
+        <div>
+          <strong>Installing:</strong>
+          <span id="swu-progress-name"></span>
+          <span id="swu-progress-value" class="pull-right"></span>
+        </div>
+        <div class="progress">
+          <div id="swu-progress-bar" class="progress-bar" role="progressbar"></div>
+        </div>
+      </div>
+     </div>
+
+    <!-- Status -->
+    <div class="row">
+      <div class="col-lg-12 col-md-12 col-xs-12">
+        <div id="swu-success" class="alert alert-success" hidden="hidden">
+          <span class="glyphicon glyphicon-ok"></span> Successful updated
+        </div>
+        <div id="swu-failure" class="alert alert-danger" hidden="hidden">
+          <span class="glyphicon glyphicon glyphicon-remove"></span> Update failed
+        </div>
+      </div>
+    </div>
+
+    <!-- Messages -->
+    <div class="row">
+      <div class="col-lg-12 col-md-12 col-xs-12">
+        <div class="panel-group">
+          <div class="panel panel-default">
+            <div class="panel-heading">
+              <h4 class="panel-title">
+                <a class="collapsed" data-toggle="collapse" href="#collapse" aria-expanded="false">Details</a>
+              </h4>
+            </div>
+            <div id="collapse" class="panel-collapse collapse">
+              <div class="panel-body" id="messages"></div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <!-- Restart -->
+    <div id="swu-restart" class="modal fade" tabindex="-1" role="dialog">
+      <div class="modal-dialog modal-sm" role="document">
+        <div class="modal-content">
+          <div class="modal-body">
+            <div class="row">
+              <div class="col-md-4">
+                <div  class="loader"></div>
+              </div>
+              <div class="col-md-8">
+              <p>The system will restart. Please be patient, as restarting takes about one minute.</p>
+            </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</body>
+
+</html>
\ No newline at end of file
diff --git a/www2/logo.png b/www2/logo.png
new file mode 100644
index 0000000000000000000000000000000000000000..12ee4c41284a56a092499d4452641f6ef67fec83
GIT binary patch
literal 24403
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

literal 0
HcmV?d00001

diff --git a/www2/package.json b/www2/package.json
new file mode 100755
index 0000000..4dc22e1
--- /dev/null
+++ b/www2/package.json
@@ -0,0 +1,38 @@ 
+{
+  "name": "swupdate",
+  "version": "0.1.0",
+  "description": "",
+  "main": "index.html",
+  "scripts": {
+    "htmlhint": "htmlhint *.html",
+    "standard": "standard --fix *.js",
+    "lint": "standard && htmlhint",
+    "build": "gulp",
+    "clean": "gulp clean"
+  },
+  "author": "",
+  "license": "MIT",
+  "devDependencies": {
+    "del": "^3.0.0",
+    "gulp": "^3.9.1",
+    "gulp-clean-css": "^3.9.0",
+    "gulp-favicons": "^2.2.7",
+    "gulp-html-replace": "^1.6.2",
+    "gulp-htmlmin": "^3.0.0",
+    "gulp-minify": "^2.1.0",
+    "gulp-rename": "^1.2.2",
+    "gulp-responsive": "^2.8.0",
+    "htmlhint": "^0.9.13",
+    "standard": "^10.0.3"
+  },
+  "dependencies": {
+    "bootstrap": "^3.3.7",
+    "dropzone": "5.2.0",
+    "jquery": "^3.2.1"
+  },
+  "standard": {
+    "ignore": [
+      "dist"
+    ]
+  }
+}
diff --git a/www2/recovery.css b/www2/recovery.css
new file mode 100755
index 0000000..3fe3492
--- /dev/null
+++ b/www2/recovery.css
@@ -0,0 +1,36 @@ 
+h1 img {
+  margin-left: 10px;
+  margin-right: 10px;
+}
+
+.dropzone .dz-preview .dz-image {
+  width: 240px;
+}
+
+.loader {
+  border: 10px solid LightGray; /* Light grey */
+  border-top: 10px solid Black; /* Blue */
+  border-bottom: 10px solid Black; /* Blue */
+  border-radius: 50%;
+  width: 80px;
+  height: 80px;
+  animation: spin 2s linear infinite;
+}
+
+@keyframes spin {
+  0% { transform: rotate(0deg); }
+  100% { transform: rotate(360deg); }
+}
+
+.panel-group .panel-title>a:before {
+  font-family: 'Glyphicons Halflings';
+  content: "\e114";
+  display: inline-block;
+  font-size: 13px;
+  margin-right: 8px;
+  text-align: center;
+}
+
+.panel-group .panel-title>a.collapsed:before {
+  content: "\e080";
+}
diff --git a/www2/recovery.js b/www2/recovery.js
new file mode 100755
index 0000000..9836831
--- /dev/null
+++ b/www2/recovery.js
@@ -0,0 +1,110 @@ 
+/*
+ * Copyright (C) 2017 Weidmüller Interface GmbH & Co. KG
+ * Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+/* global $, Dropzone, WebSocket */
+
+function restart () {
+  $.post('restart', {}, function (data) {
+    showRestart()
+  })
+};
+
+function showRestart () {
+  $('#swu-restart').modal({backdrop: 'static', keyboard: false})
+  window.setTimeout(tryReload, 3000)
+}
+function tryReload () {
+  $.ajax({
+    cache: false,
+    timeout: 1000,
+    success: function (response) {
+      window.location.reload(true)
+    },
+    error: function (xhr, textStatus, errorThrown) {
+      if (textStatus === 'timeout') { tryReload() }
+      window.setTimeout(tryReload, 1000)
+    }
+  })
+}
+
+Dropzone.options.dropzone = {
+  clickable: true,
+  acceptedFiles: '.swu'
+}
+
+window.onload = function () {
+  var protocol
+
+  if (window.location.protocol === 'https:') { protocol = 'wss:' } else { protocol = 'ws:' }
+
+  var ws = new WebSocket(protocol + '//' + window.location.host + '/ws')
+
+  ws.onclose = function (event) {
+    showRestart()
+  }
+
+  ws.onmessage = function (event) {
+    var msg = JSON.parse(event.data)
+
+    switch (msg.type) {
+      case 'message':
+        if (msg.level <= 3) {
+          $('#messages').append('<p class="text-danger">' + msg.text + '</p>')
+        } else {
+          $('#messages').append('<p>' + msg.text + '</p>')
+        }
+        break
+      case 'status':
+        switch (msg.status) {
+          case 'START':
+            $('#swu-progress').hide()
+            $('#swu-success').hide()
+            $('#swu-failure').hide()
+            $('#swu-warning').show()
+            break
+          case 'RUN':
+            break
+          case 'SUCCESS':
+            $('#swu-progress').hide()
+            $('#swu-warning').hide()
+            $('#swu-failure').hide()
+            $('#swu-success').show()
+            if ($('#swu-auto-restart').prop('checked')) { restart() }
+            break
+          case 'FAILURE':
+            $('#swu-progress').hide()
+            $('#swu-warning').hide()
+            $('#swu-success').hide()
+            $('#swu-failure').show()
+            break
+          case 'DONE':
+            $('#swu-progress').hide()
+            $('#swu-warning').hide()
+            $('#swu-success').hide()
+            $('#swu-failure').hide()
+            break
+          default:
+            console.log(msg)
+            break
+        }
+        break
+      case 'source':
+        break
+      case 'step':
+        var percent = Math.round((100 * (Number(msg.step) - 1) + Number(msg.percent)) / Number(msg.number))
+
+        $('#swu-progress-value').html(percent + '%' + ' (' + msg.step + ' of ' + msg.number + ')')
+        $('#swu-progress-name').html(msg.name)
+        $('#swu-progress-bar')
+        .css('width', percent + '%')
+        .attr('aria-valuenow', percent)
+
+        $('#swu-progress').show()
+        break
+    }
+  }
+}