Nice update/register panels

This commit is contained in:
Fabrice Marsaud
2015-05-05 18:53:35 +02:00
parent 26cc812f82
commit c8b0351786
5 changed files with 184 additions and 23 deletions

View File

@@ -111,9 +111,10 @@ nav.navbar.navbar-inverse.navbar-fixed-top(role = 'navigation')
li
a(ui-sref="settings.update")
i.fa.fa-question-circle.text-warning(ng-if = '!navbar.updater.state', tooltip = 'No update information available')
i.fa.fa-question-circle.text-info(ng-if = 'navbar.updater.state == "connected"', tooltip = 'Update information may be available')
i.fa.fa-check.text-success(ng-if = 'navbar.updater.state == "upToDate"', tooltip = 'Your XOA is up-to-date (*.*)')
i.fa.fa-bell.text-primary(ng-if = 'navbar.updater.state == "updateNeeded"', tooltip = 'You need to update your XOA (new version *.* is available)')
i.fa.fa-bell-slash.text-info(ng-if = 'navbar.updater.state == "registerNeeded"', tooltip = 'Your XOA is not registered for updates')
i.fa.fa-bell.text-primary(ng-if = 'navbar.updater.state == "upgradeNeeded"', tooltip = 'You need to update your XOA (new version *.* is available)')
i.fa.fa-bell-slash.text-warning(ng-if = 'navbar.updater.state == "registerNeeded"', tooltip = 'Your XOA is not registered for updates')
i.fa.fa-exclamation-triangle.text-danger(ng-if = 'navbar.updater.state == "error"', tooltip = 'Can\'t fetch update information')
li

View File

@@ -1,12 +1,13 @@
import angular from 'angular';
import uiRouter from 'angular-ui-router';
import angular from 'angular'
import uiRouter from 'angular-ui-router'
import ansiUp from 'ansi_up'
import updater from '../../updater';
import xoApi from 'xo-api';
import xoServices from 'xo-services';
import updater from '../../updater'
import {AuthenticationFailed} from '../../updater'
import xoApi from 'xo-api'
import xoServices from 'xo-services'
import view from './view';
import view from './view'
export default angular.module('settings.update', [
uiRouter,
@@ -29,8 +30,24 @@ export default angular.module('settings.update', [
return $sce.trustAsHtml(ansiUp.ansi_to_html(input))
}
})
.controller('SettingsUpdate', function (xoApi, xo, updater) {
.controller('SettingsUpdate', function (xoApi, xo, updater, register) {
this.updater = updater
this.register = register
this.register.isRegistered()
.then(() => this.updater.on('end', () => {
if (this.updater.state === 'registerNeeded' && this.register.state !== 'unregistered' && this.register.state !== 'error') {
this.register.isRegistered()
}
}))
this.authFailed = false
this.registerXoa = (email, password) => {
this.regPwd = ''
this.register.register(email, password)
.then(() => this.updater.verify())
.catch(AuthenticationFailed, () => {})
}
})
.name
;

View File

@@ -9,13 +9,25 @@
i.fa.fa-globe(style="color: #e25440;")
| Status
.panel-body
p(ng-if = '!ctrl.updater.state') No update information available
p(ng-if = '!ctrl.updater.state')
a.btn.btn-warning: i.fa.fa-question-circle(ng-if = '!ctrl.updater.state', tooltip = 'No update information available')
|  No update information available
.form-group(ng-if = 'ctrl.updater.state && ctrl.updater.state === "registerNeeded"')
p registerNeeded
a.btn.btn-warning(ng-if = 'ctrl.updater.state === "registerNeeded"'): i.fa.fa-bell-slash(tooltip = 'Your XOA is not registered for updates')
|   Register needed
.form-group(ng-if = 'ctrl.updater.state && ctrl.updater.state !== "registerNeeded"')
button.btn.btn-info(type = 'button', ng-click = 'ctrl.updater.verify()') Check for updates
a.btn.btn-info(ng-if = 'ctrl.updater.state === "connected"'): i.fa.fa-question-circle(tooltip = 'Update information may be available')
a.btn.btn-success(ng-if = 'ctrl.updater.state === "upToDate"'): i.fa.fa-check(tooltip = 'Your XOA is up-to-date (*.*)')
a.btn.btn-primary(ng-if = 'ctrl.updater.state === "upgradeNeeded"'): i.fa.fa-bell(tooltip = 'You need to update your XOA (new version *.* is available)')
a.btn.btn-danger(ng-if = 'ctrl.updater.state === "error"'): i.fa.fa-exclamation-triangle(tooltip = 'Can\'t fetch update information')
|  
button.btn.primary(type = 'button', ng-click = 'ctrl.updater.update()', ng-class = '{disabled: ctrl.updater.state !== "updateNeeded"}') Update
button.btn.btn-info(type = 'button', ng-click = 'ctrl.updater.verify()')
| Check for updates 
i.fa.fa-refresh
|  
button.btn.btn-primary(ng-if = 'ctrl.updater.state === "upgradeNeeded"', type = 'button', ng-click = 'ctrl.updater.update()')
| Upgrade 
i.fa.fa-cogs
div
p(ng-repeat = 'entry in ctrl.updater._log')
strong(ng-class = '{"text-danger": entry.level === "error", "text-muted": entry.level === "info", "text-warning": entry.level === "warning", "text-success": entry.level === "success"}') {{ entry.date }}
@@ -27,5 +39,28 @@
i.fa.fa-star(style="color: #e25440;")
| Registration
.panel-body.text-center
p Registration needed.
p Or Regitration status (OK etc.)
//- p {{ ctrl.register.state }} {{ ctrl.register.state === "error" }}
.text-warning(ng-if = 'ctrl.register.state === "unknown"') No registration information available.
div(ng-if = 'ctrl.register.state === "error"')
.text-danger Can't fetch registration information.
br
.text-danger {{ ctrl.register.error }}
br
button.btn.btn-default(type = 'button', ng-click = 'ctrl.register.isRegistered()')
| Refresh 
i.fa.fa-refresh
form(ng-if = 'ctrl.register.state === "unregistered"', ng-submit = 'ctrl.registerXoa(ctrl.regEmail, ctrl.regPwd)')
p.form-static-control Your Xen Orchestra appliance is not registered.
.form-group
label.sr-only(for = 'regEmail') Email
input#regEmail.form-control(type = 'email', placeholder = 'Email', ng-model = 'ctrl.regEmail', required)
.form-group
label.sr-only(for = 'regPwd') Email
input#regPwd.form-control(type = 'password', placeholder = 'Password', ng-model = 'ctrl.regPwd', required)
.form-group
button.btn.btn-primary(type = 'submit') Register
p.form-static-control.text-danger {{ ctrl.register.error }}
p(ng-if = 'ctrl.register.state === "registered"')
| Your Xen Orchestra appliance is registered to
span.text-primary {{ ctrl.register.token.registrationEmail }}
| .

View File

@@ -1,8 +1,43 @@
import angular from 'angular'
import Bluebird from 'bluebird'
import {EventEmitter} from 'events'
import * as format from '@julien-f/json-rpc/format'
import makeError from 'make-error'
import parse from '@julien-f/json-rpc/parse'
import Socket from 'socket.io-client'
function jsonRpcCall (socket, method, params = {}) {
let resolver, rejecter
const promise = new Bluebird((resolve, reject) => {
resolver = resolve
rejecter = reject
})
socket.emit(
'jsonrpc',
format.request(method, params),
message => {
const {result, error} = parse(message)
if (result) {
resolver(result)
} else if (error) {
rejecter(error)
} else {
throw new Error('Unexpected response')
}
}
)
return promise
}
function jsonRpcNotify (socket, method, params = {}) {
socket.emit(
'jsonrpc',
format.notification(method, params)
)
}
export const NotRegistered = makeError('NotRegistered')
export const AuthenticationFailed = makeError('AuthenticationFailed')
export default angular.module('updater', [])
.factory('updater', function ($interval) {
@@ -30,12 +65,11 @@ export default angular.module('updater', [])
this._connection = new Bluebird((resolve, reject) => {
const socket = new Socket('http://localhost:9001')
socket.on('print', content => {
this.emit('print', content)
Array.isArray(content) || (content = [content])
content.forEach(elem => this.log('info', elem))
this.emit('print', content)
})
socket.on('end', end => {
this.emit('end', end)
this._lowState = end
switch (this._lowState.state) {
case 'xoa-up-to-date':
@@ -45,7 +79,7 @@ export default angular.module('updater', [])
break
case 'xoa-update-needed':
case 'updater-update-needed':
this.state = 'updateNeeded'
this.state = 'upgradeNeeded'
break
case 'register-needed':
this.state = 'registerNeeded'
@@ -58,21 +92,24 @@ export default angular.module('updater', [])
}
this.log(end.level, end.message)
this._lastRun = Date.now()
this.emit('end', end)
})
socket.on('error', error => {
this.log('error', error.message)
this.emit('error', error)
this._lowState = error
this.state = 'error'
this.emit('error', error)
})
socket.on('connected', connected => {
this.log('info', connected)
this.emit('connected', connected)
this.state = 'connected'
resolve(socket)
this.emit('connected', connected)
})
socket.on('disconnect', () => {
socket.removeAllListeners()
this._connection = null
this._lowState = null
this.state = null
this.emit('disconnect')
})
})
return this._connection
@@ -81,7 +118,7 @@ export default angular.module('updater', [])
_update (update = false) {
this._open()
.then(socket => socket.emit('jsonrpc', '{"jsonrpc":"2.0","method":"main", "params": {"update": ' + update + '}}'))
.then(socket => jsonRpcNotify(socket, 'main', {update}))
}
start () {
@@ -123,4 +160,73 @@ export default angular.module('updater', [])
return new Updater()
})
.factory('register', function () {
class Register {
constructor () {
this._connection = null
this.token = null
this.state = 'unknown'
this.error = ''
}
_open () {
if (this._connection) {
return this._connection
} else {
this._connection = new Bluebird((resolve, reject) => {
const socket = new Socket('http://localhost:9002')
socket.on('connected', connected => {
resolve(socket)
})
})
return this._connection
}
}
isRegistered () {
return this._open()
.then(socket => {
return jsonRpcCall(socket, 'isRegistered')
.then(token => {
if (token.registrationToken === undefined) {
throw new NotRegistered('Your Xen Orchestra Appliance is not registered')
} else {
this.state = 'registered'
this.token = token
return token
}
})
})
.catch(NotRegistered, () => this.state = 'unregistered')
.catch(error => {
this.error = error.message
this.state = 'error'
})
}
register (email, password) {
return this._open()
.then(socket => {
return jsonRpcCall(socket, 'register', {email, password})
.then(token => {
this.state = 'registered'
this.token = token
return token
})
})
.catch(error => {
if (error.code && error.code === 1) {
this.error = 'Authentication failed'
throw new AuthenticationFailed('Authentication failed')
} else {
this.error = error.message
this.state = 'error'
}
})
}
}
return new Register()
})
.name

View File

@@ -10,6 +10,7 @@
"web"
],
"devDependencies": {
"@julien-f/json-rpc": "^0.4.3",
"angular": "^1.3.15",
"angular-animate": "^1.3.15",
"angular-bootstrap": "^0.12.0",
@@ -49,6 +50,7 @@
"lodash.indexof": "^3.0.2",
"lodash.sortby": "^3.1.0",
"lodash.throttle": "^3.0.1",
"make-error": "^1.0.2",
"novnc-node": "^0.5.1",
"rimraf": "^2.3.2",
"socket.io-client": "^1.3.5",