diff --git a/res/app/components/stf/install/install-error-filter.js b/res/app/components/stf/install/install-error-filter.js index a484c42c..b68d2829 100644 --- a/res/app/components/stf/install/install-error-filter.js +++ b/res/app/components/stf/install/install-error-filter.js @@ -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) + } } } diff --git a/res/app/components/stf/transaction/index.js b/res/app/components/stf/transaction/index.js index 277dfd29..4dce00dd 100644 --- a/res/app/components/stf/transaction/index.js +++ b/res/app/components/stf/transaction/index.js @@ -1,4 +1,5 @@ module.exports = angular.module('stf/transaction', [ require('stf/socket').name ]) + .constant('TransactionError', require('./transaction-error')) .factory('TransactionService', require('./transaction-service')) diff --git a/res/app/components/stf/transaction/transaction-error.js b/res/app/components/stf/transaction/transaction-error.js new file mode 100644 index 00000000..eff2e950 --- /dev/null +++ b/res/app/components/stf/transaction/transaction-error.js @@ -0,0 +1,4 @@ +module.exports = function TransactionError(result) { + this.message = this.code = result.error + this.result = result +} diff --git a/res/app/components/stf/transaction/transaction-service.js b/res/app/components/stf/transaction/transaction-service.js index 7e82dd88..681094ba 100644 --- a/res/app/components/stf/transaction/transaction-service.js +++ b/res/app/components/stf/transaction/transaction-service.js @@ -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 } diff --git a/res/app/components/stf/user/group/group-service.js b/res/app/components/stf/user/group/group-service.js index 3e3d972d..99b5c242 100644 --- a/res/app/components/stf/user/group/group-service.js +++ b/res/app/components/stf/user/group/group-service.js @@ -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 diff --git a/res/app/control-panes/dashboard/install/install-controller.js b/res/app/control-panes/dashboard/install/install-controller.js index 41f36aac..37dbfe8d 100644 --- a/res/app/control-panes/dashboard/install/install-controller.js +++ b/res/app/control-panes/dashboard/install/install-controller.js @@ -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' -// }) - } diff --git a/res/app/control-panes/dashboard/install/install.jade b/res/app/control-panes/dashboard/install/install.jade index 13cf4d42..67da4b18 100644 --- a/res/app/control-panes/dashboard/install/install.jade +++ b/res/app/control-panes/dashboard/install/install.jade @@ -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 }})