mirror of
https://github.com/openstf/stf
synced 2025-10-05 10:39:25 +02:00
Refactor installation to work out a few bugs and to make it cleaner. Transactions now reject on fail-responses, still need to update other places.
This commit is contained in:
parent
f91bf901fa
commit
c5a4727ae3
7 changed files with 159 additions and 233 deletions
|
@ -5,6 +5,19 @@ var responses = require('./response-codes.json')
|
|||
|
||||
module.exports = function installErrorFilter(gettext) {
|
||||
return function (text) {
|
||||
return gettext(responses[text] || text)
|
||||
switch (text) {
|
||||
case 'fail_invalid_app_file':
|
||||
return gettext('Uploaded file is not valid.')
|
||||
case 'fail_download':
|
||||
return gettext('Failed to download specified URL.')
|
||||
case 'fail_invalid_url':
|
||||
return gettext('The specified URL is invalid.')
|
||||
case 'fail':
|
||||
return gettext('Upload failed to due unknown error.')
|
||||
case 'timeout':
|
||||
return gettext('Installation timed out.')
|
||||
default:
|
||||
return gettext(responses[text] || text)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
module.exports = angular.module('stf/transaction', [
|
||||
require('stf/socket').name
|
||||
])
|
||||
.constant('TransactionError', require('./transaction-error'))
|
||||
.factory('TransactionService', require('./transaction-service'))
|
||||
|
|
4
res/app/components/stf/transaction/transaction-error.js
Normal file
4
res/app/components/stf/transaction/transaction-error.js
Normal file
|
@ -0,0 +1,4 @@
|
|||
module.exports = function TransactionError(result) {
|
||||
this.message = this.code = result.error
|
||||
this.result = result
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
var Promise = require('bluebird')
|
||||
var uuid = require('node-uuid')
|
||||
|
||||
module.exports = function TransactionServiceFactory(socket) {
|
||||
module.exports = function TransactionServiceFactory(socket, TransactionError) {
|
||||
var transactionService = {}
|
||||
|
||||
function createChannel() {
|
||||
|
@ -126,20 +126,21 @@ module.exports = function TransactionServiceFactory(socket) {
|
|||
if (seq === last) {
|
||||
result.success = message.success
|
||||
|
||||
if (message.success) {
|
||||
if (message.data) {
|
||||
result.lastData = result.data[seq] = message.data
|
||||
}
|
||||
}
|
||||
else {
|
||||
result.lastData = result.error = message.data
|
||||
}
|
||||
|
||||
if (message.body) {
|
||||
result.body = JSON.parse(message.body)
|
||||
}
|
||||
|
||||
resolver.resolve(result)
|
||||
if (result.success) {
|
||||
if (message.data) {
|
||||
result.lastData = result.data[seq] = message.data
|
||||
}
|
||||
resolver.resolve(result)
|
||||
}
|
||||
else {
|
||||
result.lastData = result.error = message.data
|
||||
resolver.reject(new TransactionError(result))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
else {
|
||||
|
@ -196,6 +197,9 @@ module.exports = function TransactionServiceFactory(socket) {
|
|||
this.device = this.source
|
||||
}
|
||||
|
||||
DeviceTransactionResult.prototype = Object.create(TransactionResult)
|
||||
DeviceTransactionResult.constructor = DeviceTransactionResult
|
||||
|
||||
transactionService.create = function(target, options) {
|
||||
if (options && !options.result) {
|
||||
options.result = TransactionResult
|
||||
|
@ -234,7 +238,5 @@ module.exports = function TransactionServiceFactory(socket) {
|
|||
})
|
||||
}
|
||||
|
||||
transactionService.TransactionResult = TransactionResult
|
||||
|
||||
return transactionService
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ var Promise = require('bluebird')
|
|||
module.exports = function GroupServiceFactory(
|
||||
socket
|
||||
, TransactionService
|
||||
, TransactionError
|
||||
) {
|
||||
var groupService = {
|
||||
}
|
||||
|
@ -21,12 +22,13 @@ module.exports = function GroupServiceFactory(
|
|||
}
|
||||
}
|
||||
})
|
||||
return tx.promise.then(function(result) {
|
||||
if (!result.success) {
|
||||
return tx.promise
|
||||
.then(function(result) {
|
||||
return result.device
|
||||
})
|
||||
.catch(TransactionError, function() {
|
||||
throw new Error('Device refused to join the group')
|
||||
}
|
||||
return result.device
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
groupService.kick = function (device, force) {
|
||||
|
@ -43,12 +45,13 @@ module.exports = function GroupServiceFactory(
|
|||
}
|
||||
}
|
||||
})
|
||||
return tx.promise.then(function(result) {
|
||||
if (!result.success) {
|
||||
throw new Error('Device refused to be kicked from the group')
|
||||
}
|
||||
return result.device
|
||||
})
|
||||
return tx.promise
|
||||
.then(function(result) {
|
||||
return result.device
|
||||
})
|
||||
.catch(TransactionError, function() {
|
||||
throw new Error('Device refused to join the group')
|
||||
})
|
||||
}
|
||||
|
||||
return groupService
|
||||
|
|
|
@ -1,51 +1,76 @@
|
|||
module.exports = function InstallCtrl(
|
||||
$scope
|
||||
, $http
|
||||
, SettingsService
|
||||
, $filter
|
||||
, StorageService
|
||||
) {
|
||||
$scope.upload = null
|
||||
$scope.installation = null
|
||||
$scope.installEnabled = true
|
||||
$scope.launchEnabled = true
|
||||
function Installation(progress, state) {
|
||||
this.progress = progress
|
||||
this.state = state
|
||||
this.settled = false
|
||||
this.success = false
|
||||
this.error = null
|
||||
this.href = null
|
||||
this.manifest = null
|
||||
this.launch = true
|
||||
|
||||
this.update = function(progress, state) {
|
||||
console.log('UPDATE', progress, state)
|
||||
$scope.safeApply(function () {
|
||||
this.progress = Math.floor(progress)
|
||||
this.state = state
|
||||
}.bind(this))
|
||||
}
|
||||
|
||||
this.okay = function(state) {
|
||||
console.log('OKAY', state)
|
||||
$scope.safeApply(function () {
|
||||
this.settled = true
|
||||
this.progress = 100
|
||||
this.success = true
|
||||
this.state = state
|
||||
}.bind(this))
|
||||
}
|
||||
|
||||
this.fail = function(err) {
|
||||
console.log('FAIL', err, this)
|
||||
$scope.safeApply(function () {
|
||||
this.settled = true
|
||||
this.progress = 100
|
||||
this.success = false
|
||||
this.error = err
|
||||
}.bind(this))
|
||||
}
|
||||
}
|
||||
|
||||
$scope.accordionOpen = true
|
||||
|
||||
$scope.clear = function () {
|
||||
$scope.upload = null
|
||||
$scope.installation = null
|
||||
$scope.accordionOpen = false
|
||||
}
|
||||
|
||||
$scope.installUrl = function (url) {
|
||||
$scope.upload = {
|
||||
progress: 0,
|
||||
lastData: 'uploading'
|
||||
}
|
||||
|
||||
$scope.installation = null
|
||||
var installation = $scope.installation = new Installation(0, 'uploading')
|
||||
return $scope.control.uploadUrl(url)
|
||||
.progressed(function (uploadResult) {
|
||||
$scope.$apply(function () {
|
||||
$scope.upload = uploadResult
|
||||
})
|
||||
installation.update(uploadResult.progress / 2, uploadResult.lastData)
|
||||
})
|
||||
.then(function (uploadResult) {
|
||||
$scope.$apply(function () {
|
||||
$scope.upload = uploadResult
|
||||
})
|
||||
|
||||
if (uploadResult.success) {
|
||||
return $scope.maybeInstall(uploadResult.body)
|
||||
}
|
||||
installation.update(uploadResult.progress / 2, uploadResult.lastData)
|
||||
installation.manifest = uploadResult.body
|
||||
return $scope.install(installation)
|
||||
})
|
||||
.then(function() {
|
||||
installation.okay('installed')
|
||||
})
|
||||
.catch(function(err) {
|
||||
installation.fail(err.code || err.message)
|
||||
})
|
||||
}
|
||||
|
||||
$scope.installFile = function ($files) {
|
||||
$scope.$apply(function () {
|
||||
$scope.upload = {
|
||||
progress: 0
|
||||
, lastData: 'uploading'
|
||||
}
|
||||
})
|
||||
|
||||
var installation = $scope.installation = new Installation(0, 'uploading')
|
||||
return StorageService.storeFile('apk', $files, {
|
||||
filter: function(file) {
|
||||
return /\.apk$/i.test(file.name)
|
||||
|
@ -53,144 +78,45 @@ module.exports = function InstallCtrl(
|
|||
})
|
||||
.progressed(function(e) {
|
||||
if (e.lengthComputable) {
|
||||
$scope.$apply(function () {
|
||||
$scope.upload = {
|
||||
progress: e.loaded / e.total * 100
|
||||
, lastData: 'uploading'
|
||||
}
|
||||
})
|
||||
installation.update(e.loaded / e.total * 100 / 2, 'uploading')
|
||||
}
|
||||
})
|
||||
.then(function(res) {
|
||||
$scope.$apply(function () {
|
||||
$scope.upload = {
|
||||
progress: 100
|
||||
, lastData: 'processing'
|
||||
}
|
||||
})
|
||||
|
||||
var href = res.data.resources.file.href
|
||||
|
||||
return $http.get(href + '/manifest')
|
||||
installation.update(100 / 2, 'processing')
|
||||
installation.href = res.data.resources.file.href
|
||||
return $http.get(installation.href + '/manifest')
|
||||
.then(function(res) {
|
||||
$scope.upload = {
|
||||
progress: 100
|
||||
, lastData: 'success'
|
||||
, settled: true
|
||||
}
|
||||
|
||||
if (res.data.success) {
|
||||
return $scope.maybeInstall({
|
||||
href: href
|
||||
, launch: $scope.launchEnabled
|
||||
, manifest: res.data.manifest
|
||||
})
|
||||
installation.manifest = res.data.manifest
|
||||
return $scope.install(installation)
|
||||
}
|
||||
else {
|
||||
throw new Error('Unable to retrieve manifest')
|
||||
}
|
||||
})
|
||||
})
|
||||
.then(function() {
|
||||
installation.okay('installed')
|
||||
})
|
||||
.catch(function(err) {
|
||||
$scope.$apply(function () {
|
||||
if (err.code === 'no_input_files') {
|
||||
$scope.upload = null
|
||||
}
|
||||
else {
|
||||
$scope.upload = {
|
||||
progress: 100
|
||||
, lastData: 'fail'
|
||||
, settled: true
|
||||
, error: err.message
|
||||
}
|
||||
}
|
||||
})
|
||||
installation.fail(err.code || err.message)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
$scope.maybeInstall = function (options) {
|
||||
if ($scope.installEnabled) {
|
||||
|
||||
if ($scope.installation) {
|
||||
$scope.installation.lastData = null
|
||||
}
|
||||
$scope.accordionOpen = true
|
||||
|
||||
return $scope.control.install(options)
|
||||
.progressed(function (installResult) {
|
||||
$scope.$apply(function () {
|
||||
installResult.manifest = options.manifest
|
||||
$scope.installation = installResult
|
||||
})
|
||||
})
|
||||
.then(function (installResult) {
|
||||
$scope.$apply(function () {
|
||||
$scope.accordionOpen = false
|
||||
installResult.manifest = options.manifest
|
||||
$scope.treeData = installResult.manifest
|
||||
$scope.installation = installResult
|
||||
$scope.installationError = installResult.error
|
||||
})
|
||||
})
|
||||
}
|
||||
else {
|
||||
return Promise.reject(new Error('Installation not enabled'))
|
||||
}
|
||||
$scope.install = function (installation) {
|
||||
return $scope.control.install(installation)
|
||||
.progressed(function (result) {
|
||||
installation.update(50 + result.progress / 2, result.lastData)
|
||||
})
|
||||
}
|
||||
|
||||
$scope.uninstall = function (packageName) {
|
||||
// TODO: After clicking uninstall accordion opens
|
||||
return $scope.control.uninstall(packageName)
|
||||
.then(function (result) {
|
||||
if (result.success) {
|
||||
$scope.$apply(function () {
|
||||
$scope.clear()
|
||||
})
|
||||
} else {
|
||||
console.error(result.error)
|
||||
}
|
||||
.then(function () {
|
||||
$scope.$apply(function () {
|
||||
$scope.clear()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
$scope.taskFinished = function () {
|
||||
if ($scope.installEnabled) {
|
||||
return $scope.upload && ($scope.upload.error || $scope.upload.settled &&
|
||||
$scope.installation && $scope.installation.settled)
|
||||
} else {
|
||||
return $scope.upload && $scope.upload.settled
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
$scope.taskProgress = function () {
|
||||
var progress = 0
|
||||
if ($scope.installEnabled) {
|
||||
if ($scope.upload) {
|
||||
progress += $scope.upload.progress
|
||||
}
|
||||
if ($scope.installation) {
|
||||
progress += $scope.installation.progress
|
||||
}
|
||||
progress = Math.floor(progress / 2)
|
||||
} else {
|
||||
if ($scope.upload) {
|
||||
progress = $scope.upload.progress
|
||||
}
|
||||
}
|
||||
return progress
|
||||
}
|
||||
|
||||
$scope.accordionOpen = true
|
||||
|
||||
//
|
||||
// $scope.installEnabled = true
|
||||
// SettingsService.bind($scope, {
|
||||
// key: 'installEnabled',
|
||||
// storeName: 'Upload'
|
||||
// })
|
||||
//
|
||||
// //$scope.launchEnabled = true
|
||||
// SettingsService.bind($scope, {
|
||||
// key: 'launchEnabled',
|
||||
// storeName: 'Upload'
|
||||
// })
|
||||
|
||||
}
|
||||
|
|
|
@ -2,18 +2,9 @@
|
|||
.heading
|
||||
i.fa.fa-upload
|
||||
span(translate) App Upload
|
||||
clear-button(ng-click='clear()', ng-disabled='!installation && !upload').btn-xs
|
||||
//label.checkbox-inline.pull-right
|
||||
input(type='checkbox', ng-model='launchEnabled')
|
||||
span Launch
|
||||
//label.checkbox-inline.pull-right
|
||||
input(type='checkbox', ng-model='installEnabled')
|
||||
span(translate) Install
|
||||
clear-button(ng-click='clear()', ng-disabled='!installation').btn-xs
|
||||
|
||||
.widget-content.padded
|
||||
//.widget-content.padded(style='padding: 0; padding-bottom: 15px;')
|
||||
|
||||
//.col-md-10.col-md-offset-1
|
||||
.widget-content.padded()
|
||||
//.input-group.form-inline
|
||||
input(type=text, ng-model='remoteUrl', ng-enter='installUrl(remoteUrl)',
|
||||
placeholder='http://...').form-control
|
||||
|
@ -28,59 +19,45 @@
|
|||
i.fa.fa-2x.fa-download.drop-area-icon
|
||||
.drop-area-text(translate) Drop file to upload
|
||||
|
||||
.upload-status(ng-if='upload || installation')
|
||||
.upload-status(ng-if='installation')
|
||||
progressbar(max='100', value='installation.progress', ng-if='!installation.settled',
|
||||
ng-class='{"active": !installation.settled}').progress-striped
|
||||
|
||||
accordion(close-others='false').pointer
|
||||
accordion-group(is-open='accordionOpen', is-disabled='accordionDisabled')
|
||||
accordion-heading.pointer
|
||||
i.fa.fa-file-o
|
||||
span {{installation.manifest.package || "App" }}
|
||||
|
||||
button.btn.btn-xs.btn-danger-outline.pull-right(
|
||||
ng-click='uninstall(installation.manifest.package)', ng-show='installation.settled')
|
||||
i.fa.fa-trash-o
|
||||
span(translate) Uninstall
|
||||
|
||||
div
|
||||
span(ng-switch='upload.lastData')
|
||||
strong(ng-switch-when='uploading')
|
||||
span(translate) Uploading...
|
||||
strong(ng-switch-when='processing')
|
||||
span(translate) Processing...
|
||||
strong(ng-switch-when='fail')
|
||||
span(translate) Upload failed
|
||||
strong(ng-switch-when='success')
|
||||
span(ng-show='!installation', translate) Upload complete
|
||||
|
||||
span(ng-switch='installation.lastData')
|
||||
strong(ng-switch-when='pushing_app')
|
||||
span(translate) Pushing app...
|
||||
strong(ng-switch-when='installing_app')
|
||||
span(translate) Installing app...
|
||||
strong(ng-switch-when='launching_app')
|
||||
span(translate) Launching activity...
|
||||
strong(ng-switch-when='success')
|
||||
div(ng-if='!installation.error')
|
||||
span(ng-switch='installation.state')
|
||||
strong(ng-switch-when='uploading')
|
||||
span(translate) Uploading...
|
||||
span ({{installation.progress}}%)
|
||||
strong(ng-switch-when='processing')
|
||||
span(translate) Processing...
|
||||
span ({{installation.progress}}%)
|
||||
strong(ng-switch-when='pushing_app')
|
||||
span(translate) Pushing app...
|
||||
span ({{installation.progress}}%)
|
||||
strong(ng-switch-when='installing_app')
|
||||
span(translate) Installing app...
|
||||
span ({{installation.progress}}%)
|
||||
strong(ng-switch-when='launching_app')
|
||||
span(translate) Launching activity...
|
||||
span ({{installation.progress}}%)
|
||||
strong(ng-switch-when='installed')
|
||||
accordion(close-others='false', ng-if='installation').pointer
|
||||
accordion-group(is-open='accordionOpen')
|
||||
accordion-heading.pointer
|
||||
i.fa.fa-file-o
|
||||
span {{installation.manifest.package || "App" }}
|
||||
|
||||
button.btn.btn-xs.btn-danger-outline.pull-right(
|
||||
ng-click='uninstall(installation.manifest.package)', ng-show='installation.success')
|
||||
i.fa.fa-trash-o
|
||||
span(translate) Uninstall
|
||||
div(ng-include='"control-panes/dashboard/install/activities/activities.jade"')
|
||||
|
||||
button.btn.btn-sm.btn-primary-outline(btn-checkbox, ng-model='showManifest')
|
||||
i.fa.fa-list
|
||||
span(ng-if='showManifest') Hide Manifest
|
||||
span(ng-if='!showManifest') Show Manifest
|
||||
pre.manifest-text(ng-if='showManifest') {{ installation.manifest | json }}
|
||||
strong(ng-switch-when='fail')
|
||||
span(translate) Installation failed
|
||||
|
||||
span(ng-hide='taskFinished()') ({{taskProgress()}}%)
|
||||
|
||||
progressbar(max='100', value='taskProgress()', ng-if='!taskFinished()',
|
||||
ng-class='{"active": !taskFinished()}').progress-striped
|
||||
|
||||
|
||||
alert(type='danger', close='upload.error = null', ng-show='upload.error')
|
||||
strong(translate) Error:
|
||||
span {{ upload.error | uploadError | translate }}
|
||||
|
||||
alert(type='danger', close='installationError = undefined', ng-show='installationError')
|
||||
strong(translate) Error:
|
||||
span {{ installationError | installError | translate }} ({{ installationError }})
|
||||
alert(type='danger', close='clear()', ng-if='installation.error')
|
||||
strong(translate) Oops!
|
||||
span {{ installation.error | installError | translate }} ({{ installation.error }})
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue